Promiseها در جاوااسکریپت – بخش سوم
11 اردیبهشت
تا اینجا Promiseها در جاوااسکریپت را معرفی کردیم. نحوهی استفاده از آن را مورد بررسی قرار دادیم. گفتیم چهطور میشود Promise تعریف کرد و کتابخانههای دیگر را با این ویژگی هماهنگ کرد. یاد گرفتیم چطور میشود Promise را به کار گرفت. مفهوم زنجیربافی را شرح دادیم و با استفاده از مفاهیم شرح داده شده یک پروژه فرضی نیز شروع کردیم تا گام به گام پیش ببریم و تکمیل کنیم. در این بخش به مدیریت خطای Promiseها میپردازیم. اگر این سری مقاله را از ابتدا پیگیری نکردهاید پیشنهاد میکنم از بخش اول شروع کنید.
مدیریت خطای Promiseها
همانطور که قبلا دیدیم، متد then()
دو آرگومان میگیرد: یکی برای موفقیت و یکی برای شکست. (یا به زبان Promiseها یکی برای تحقق (resolve) و یکی برای رد شدن (reject)):
get('story.json').then(function(response) {
console.log("Hoooora!", response);
}, function(error) {
console.log("Poooof!", error);
})
همچنین میتوان از catch()
نیز استفاده کرد:
get('story.json').then(function(response) {
console.log("Hoooora!", response);
}).catch(function(error) {
console.log("Poooof!", error);
})
catch()
متد عجیب غریبی نیست. بلکه معادل then(undefined, func)
است. البته صورت خواناتری دارد. دقت کنید که دو کد بالا مثل هم رفتار نمیکنند. بلکه کد دومی معادل کد زیر است:
get('story.json').then(function(response) {
console.log("Hoooora!", response);
}).then(undefined, function(error) {
console.log("Poooof!", error);
})
تفاوت دو کد بسیار ظریف است. اما در عین حال مهم نیز هست. وقتی یک Promise ریجکت میشود، این callback ریجکت در متد then()
بعدی و یا متد catch()
است که فراخوانی میشود. پس در مورد then(func1, func2)
تنها یکی از آرگومانها فراخوانی میشود اما در مورد then(func1).catch(func2)
چون دو تابع در امتداد زنجیره قرار دارند، اگر func1
ریجکت شود، هر دوی func1
و func2
اجرا میشوند. به مثال زیر توجه کنید:
asyncThing1().then(function() {
return asyncThing2();
}).then(function() {
return asyncThing3();
}).catch(function(err) {
return asyncRecovery1();
}).then(function() {
return asyncThing4();
}, function(err) {
return asyncRecovery2();
}).catch(function(err) {
console.log("Don't worry about it");
}).then(function() {
console.log("All done!");
})
جریان کد بالا بسیار شبیه به try/catch در جاوااسکریپت است. خطاهایی که در قسمت try اتفاق میافتند بلافاصله به بلوک catch پرت میشوند. بیایید کد بالا را به شکل فلوچارت رسم کنیم:
همانطور که میبینید، اَعمال غیر همزمان، تا خط 5، به صورت پشت سر هم اتفاق افتاده است. اگر هر کدام از این اعمال resolve شود، هر عمل غیر همزمان، عمل غیر همزمان دیگر را به نوبت فراخوانی میکند. (فلشهای آبی در فلوچارت). چون در خط 5 متد catch()
را داریم، هر کجا که عملی reject شود، عمل غیر همزمان asyncRecovery1
فراخوانی میشود (فلشهای قرمز). اگر همهی اعمال تا asyncThing4
با موفقیت اجرا شوند، آرگومان اول متد then()
در خط 7 اجرا میشود که عمل غیر همزمان asyncThing4
را اجرا میکند. اگر به هر علتی سر از asyncRecovery1
درآوردیم، در صورت resolve شدن asyncRecovery1
باز asyncThing4
اجرا میشود. اما اگر این عمل غیر همزمان reject شود، آرگومان دوم متد then()
خط 7 اجرا میشود که همان asyncRecovery2
است. حالا در خط 11 متد catch()
را داریم. به این معنی که اگر هرکدام از اعمال غیر همزمان asyncThing4
یا asyncRecovery2
ریجکت شوند، این متد اجرا میشود و بعد از اجرای این متد then()
نهایی در خط 13 اجرا میشود. اگر هم هیچکدام reject نشد، متد catch()
اجرا نشده و یک راست به سراغ then()
نهایی خواهیم رفت.
رفتار Promiseها با خطاهای کد
callbackهای خطا علاوه بر اینکه هنگام reject شدن Promise فراخوانی میشوند، به طور ضمنی هنگام وجود خطا در کد نیز فراخوانی میشوند. به کد زیر توجه کنید:
var jsonPromise = new Promise(function(resolve, reject) {
// agar JSON e naa mo'tabari raa be JSON.parse
// bedahim, error midahad:
resolve(JSON.parse("in yek JSON nist"));
});
jsonPromise.then(function(data) {
// in ghesmat ejraa nemishavad:
console.log("Huraaaa!", data);
}).catch(function(err) {
// be jaye aan in ghesmat ejraa mishavad:
console.log("Poooof!", err);
})
این موضوع نشان میدهد که بهتر است کدهای مربوط به Promise را در قسمت callback آن بنویسیم. در این صورت اگر خطایی در هر قسمت از کد رخ دهد، خطاگیری به شکل اتوماتیک انجام شده و نیازی به کار اضافه نخواهد بود. همین مسأله در خطاهایی که در callback متد then()
رخ میدهد نیز صادق است:
get('/').then(JSON.parse).then(function() {
// ejraa nemishavad chon, '/' yek safheye HTML ast, na JSON
// pas JSON.parse khata midahad
console.log("Huraaaa!", data);
}).catch(function(err) {
// dar avaz in ghesmat ejraa mishavad:
console.log("Poooof!", err);
})
مدیریت خطا در عمل
برگردیم به پروژهای که تعریف کرده بودیم. میتوانیم از catch()
برای نشان دادن خطا به کاربر استفاده کنیم:
getJSON('story.json').then(function(story) {
return getJSON(story.chapterUrls[0]);
}).then(function(chapter1) {
addHtmlToPage(chapter1.html);
}).catch(function() {
addTextToPage("Khata dar neshan dadane fasl!");
}).then(function() {
document.querySelector('.spinner').style.display = 'none';
})
اگر گرفتن story.chapterUrls[0]
دچار مشکل شود، (مثلا با خطای 500 یا آفلاین بودن کاربر)، همهی callbackهای مربوط به موفقیت ریجکت میشوند که شامل یک مورد در getJSON()
است که تبدیل JSON را انجام میدهد. یکی هم مربوط به افزودن HTML به صفحه است. در عوض callback داخل catch()
در خط 5 اجرا میشود و “خطا در نشان دادن فصل!” را در صفحه چاپ میکند. همانند try/catch در جاوااسکریپت، بعد از گرفتن خطا، کدهایی که در ادامه میآیند، پردازش میشوند. بنابراین چرخانک همیشه مخفی میشود (با دستور خط 8) و این دقیقا چیزی هست که میخواهیم اتفاق بیفتد. کد بالا، در واقع، نسخهی غیر همزمان کد زیر است:
try {
var story = getJSONSync('story.json'); //Sync == Hamzaman
var chapter1 = getJSONSync(story.chapterUrls[0]);
addHtmlToPage(chapter1.html);
}
catch (e) {
addTextToPage("Khata dar neshan dadane fasl!");
}
document.querySelector('.spinner').style.display = 'none';
در اینجا ممکن است بخواهید در هر مرحله از کار، مثلا به منظور رفع باگ، برای خودتان از خطا گزارشگیری کنید؛ بدون اینکه در روند خطاگیری فعلی تغییری ایجاد شود. در این صورت بعد از گرفتن خطا باید دوباره آن را پرت (throw) کنید. مثلا اگر بخواهیم در تابع getJSON()
خطا را بگیریم و در عین حال عبارت “خطا در نشان دادن فصل!” نیز برای کاربر نشان داده شود مینویسیم:
function getJSON(url) {
return get(url).then(JSON.parse).catch(function(err) {
console.log("khata dar getJSON be khatere, ", url, err);
throw err;
});
}
پروژه را تا آنجا پیش بردیم که یک فصل را بارگزاری کردیم و آن را نشان دادیم. در بخش چهارم (آخر) مقاله به این خواهیم پرداخت که چطور همهی فصلها را بارگزاری کنیم. با من همراه باشید. اگر میخواهید به اصل مقاله دسترسی داشته باشید اینجا کلیک کنید.
19 اسفند فروش آنلاین و وردپرس فروشگاه آنلاین و فروشگاه اینترنتی
فروشگاه اینترنتی خوب و موفق چه ویژگی هایی دارد؟
اگر کسب و کار شما به گونه ای است که فکر می کنید نیاز به تاسیس یک فروشگاه اینترنتی موفق دارید، اما به لحاظ فنی ایده ای برای آن ندارید، پست من را از دست ندهید. چون سعی کرده ام تمام تجربیات چند سال اخیرم را در این مقاله جمع بندی کنم.
26 فروردین استایلبندی و CSS css
مدیا کوئریها
مدیا کوئریها (Media Query) در واقع روشی است که بتوانیم برای دستگاههای مختلف که ویژگیهای متفاوتی دارند استایلهای CSS متفاوتی را تعریف کنیم.
8 اردیبهشت وردپرس wordpress و وردپرس
چگونه در وردپرس از نیمفاصله استفاده کنیم؟
استفاده از نیمفاصله برای نگارش یک متن فارسی درست و استاندارد ضروری است. همهی ما به تعدادی Shortcut برای گذاشتن نیمفاصله عادت داریم. مثلا در نرم افزار Microsoft Word از ترکیب Ctrl و علامت منها استفاده میکنیم. اما زمانی که کار به نوشتن در وب و استفاده از وردپرس، فتوشاپ و نرمافزارهای دیگر برسد، ممکن است دچار مشکل شویم. پس چگونه در وردپرس از نیمفاصله استفاده کنیم؟
26 خرداد جاوااسکریپت data binding، اتصال داده، و جاوااسکریپت
مفاهیم اولیهی اتصال داده (data binding) در جاوااسکریپت
یکی از مهمترین الگوهای توسعهی اپلیکیشنهای جاوااسکریپتی، جدا کردن دادهها و ظاهر اپلیکیشن از همدیگر و اتصال این دو به یکدیگر به شکل یکسویه یا دوسویه است. به طوری که با تغییر داده، ظاهر مرتبط با آن داده عوض و به شکل متقابل با تغییر در ظاهر برنامه (مانند پر کردن فرم یا تغییر مکان یک شی) داده مرتبط با آن دچار تغییر شود. امروزه اتصال داده در اپلیکیشنهای تحت وب برای برنامهنویس از نان شب واجبتر است! البته فریمورکهای متداول مانند ReactJs، این اتصال داده را به خوبی برای برنامهنویسان پیشبینی کردهاند و در این مقاله قرار نیست فریمورک توسعه بدهیم. اما به دلایلی خوب است اساس و اصول اتصال داده در جاوااسکریپت را درک کنیم. برای فهمیدن این دلایل و کشف راز اتصال داده در جاوااسکریپت با من همراه شوید.