آموزش ویژگی های ECMAScript 6 (جلسه 35) : آموزش کار با Promise - قسمت 1

دسته بندی: آموزش
زمان مطالعه: 7 دقیقه
۲۵ مهر ۱۳۹۶

همونطور که اطلاع دارید در جلسه قبل بحث مربوط به Generator‌ها رو به پایان رسوندیم و شما رو بصورت کامل با اونا آشنا کردیم. در این جلسه میخوایم کار با Promise‌ها رو شروع کنیم و هر چیزی که نیاز دارید رو در اختیارتون قرار بدیم.

مشکلات قبل از Promise

قبل از اینکه Promise‌ها به وجود بیان از روشهای دیگه ای استفاده میکردیم. همونطور که اطلاع دارید دو مدل کدنویسی وجود داره:

  • Asynchronous : آسنکرون یا غیرهمزمان
  • Synchronous : سنکرون یا همزمان

بیشتر اوقات ما از مدل دوم یعنی همزمان استفاده میکنیم. به این معنی که تمام خط‌ها یکی پس از دیگری بصورت همزمان اجرا میشن. کد زیر رو در نظر بگیرید:

console.log('Mohammad');
console.log('Hassan');

همونطور که میبینید دو خط کد ساده رو وارد کردیم و میخوایم دو رشته رو در Console چاپ کنیم. این دو خط بصورت همزمان و پشت سر هم اجرا میشن و خروجی به سرعت در Console نمایش داده میشه. بصورت زیر:

میبینید که دو رشته مورد نظر به ترتیب و پشت سر هم چاپ شدند. به این مورد کدنویسی همزمان یا Asynchronous میگن.

مدیریت رویداد یا Event Handler

حالا فرض کنید که یک المنت دکمه رو در بخش HTML اضافه کنیم. بصورت زیر:

<button id="btn">CLick Me</button>

میبینید که id اون رو برابر با btn قرار دادیم تا بتونیم در Javascript به راحتی به اون دسترسی داشته باشیم. حالا یک رویداد کلیک برای این دکمه تعریف میکنیم. کد زیر رو در نظر بگیرید:

let btn = document.getElementById('btn');

console.log('Before');

btn.onclick = function() {
	console.log('Button Clicked');
};

console.log('After');

همونطور که میبینید در خط 1 با استفاده از متد getElementById به دکمه ساخته شده دسترسی پیدا کردیم. در خط 3 یک Console.log قرار دادیم و هدفمون اینه که نشون بدیم این کد قبل از کد مربوط به Event Handler قرار داده شده.

در خط 5 یک مدیریت کننده رویداد کلیک برای دکمه مورد نظر ساختیم و یک تابع بی نام یا Anonymous function رو به اون نسبت دادیم. این تابع زمانی اجرا میشه که بر روی دکمه مورد نظر کلیک بشه. پس این Event Handler بصورت اتوماتیک درون Event Loop قرار میگیره و زمانی که رویداد مورد نظر انجام بشه، این تابع اجرا میشه. با اجرا شدن تابع، یک متن Button Clicked در Console چاپ میشه.

در خط 9 نیز یک Console.log دیگه قرار داده شده تا نشون بدیم که این خط کد بعد از Event handler اجرا میشه. حالا کد بالا رو در مرورگر اجرا میکنیم. خروجی در Console بصورت زیر است:

همونطور که میبینید کدهای قبل و بعد از Event Handler اجرا شدن و رشته‌های Before و After در Console چاپ شده است. تابع بی نام مربوط به Event Handler اجرا نشده و به همین دلیل است که رشته مورد نظر در Console چاپ نشده. اگر بر روی دکمه کلیک کنیم، رشته مورد نظر در Console چاپ میشه. بصورت زیر:

همونطور که میبینید با کلیک بر روی دکمه، رشته مورد نظر چاپ میشه. پس دیدید که Event Handler‌ها بصورت غیرهمزمان هستند و یکی پس از دیگری اجرا نمیشن و رفتار Asynchronous دارند. ما برنامه نویسان خیلی با این مدل کدنویسی کار کردیم و Event Handler‌های زیادی رو به وجود آوردیم. این موارد نمونه‌های ساده ای از برنامه نویسی غیرهمزمان هستند.

مدل کدنویسی با استفاده از Event Handler‌ها کمی قدیمی شده و روشهای دیگه ای جایگزین اونا شده اند که اکثر کتابخانه‌های معروف مانند jQuery نیز از اونا استفاده میکنن. مثلا jQuery برای مدیریت رویداد کلیک از Callback استفاده میکنه.

استفاده از Callback

اگر بخوایم در کتابخانه jQuery یک رویداد کلیک برای دکمه ساخته شده در بالا تعریف کنیم، بصورت زیر عمل میکنیم:

console.log('Before');

$('#btn').on('click', function() {
	console.log('Button Clicked');
});

console.log('After');

میبینید که با استفاده از متد on، مشخص کردیم زمانی که بر روی دکمه مورد نظر کلیک میشه، تابع معرفی شده اجرا بشه و رشته مورد نظر در Console چاپ بشه. همونطور که میبینید یک تابع بعنوان آرگومان دوم به متد on قرار دادیم. به این تابع، callback میگن و هر بار که رویداد کلیک برای المنت مورد نظر رخ میده، فورا اجرا میشه.

مثالی کاربردی در مورد مشکل Callback

فرض کنید که یک تابع بنام fetch تعریف کنیم و کار اون دریافت اطلاعات از url مورد نظر باشه. برای اینکار بصورت زیر عمل میکنیم:

function fetch(url, callback) {
    var request = new XMLHttpRequest();
 
    request.open('GET', url);
 
    request.onload = function() {
        var data, error;
 
        if (reques.status === 200) {
            data = request.responseText;
        }
        else { error = new Error('request failed!'); }
 
        callback({data:data, error:error});
    };
 
    request.onerror = function(e) {
        callback({error: e});
    }
 
    try { request.send(); }
    catch (e) { callback({error: e}); }
}

میبینید که با استفاده از XMLHttpRequest و رویدادهای onload و ... این تابع رو تعریف کردیم. 2 پارامتر برای این تابع تعریف شده است. یکی url و دیگری callback.

این تابع در ابتدا به url مورد نظر متصل میشه و اطلاعات رو دریافت میکنه و بعد از اون خروجی رو به callback پاس میده. حالا برای استفاده از این تابع بصورت زیر عمل میکنیم:

fetch('/json/data.json', function(responseObj) {
    if (!responseObj.error) {
        try {
            console.log('data!', JSON.parse(responseObj.data));
        }
        catch (e) { console.error(e); }
    }
    else { console.error(responseObj.error);}
});

میبینید که آدرس مورد نظر رو تعریف کردیم و تابع callback رو قرار دادیم. درون تابع در ابتدا بررسی کردیم که ارور وجود داره یا خیر.

مشکل Callback Hell

استفاده از Callback خیلی متداول‌تر از استفاده از Event Handler است اما با این وجود مشکلات و معایب مربوط به خودش رو داره. توابع callback دو روش اصلی برای مدیریت ارور دارند. یکی استفاده از if-else و try-catch است و دیگری این که بیایم از یک callback دیگه درون callback فعلی استفاده کنیم که به اون callback hell هم میگن. کد زیر رو ببینید:

fetch('/json/data.json', function(responseObj) {
    if (!responseObj.error) {
        try {
            var data = JSON.parse(responseObj.data);
 
            console.log('main data', data);
 
            // now call `fetch` again to retrieve new data
            // based on the response data
            fetch(data.url, function(responseObjInner) {
                if (!responseObjInner.error) {
                    console.log('inner data', responseObjInner.data);
                }
                else { console.error(responseObjInner.error);}
            });
        }
        catch (e) { console.error(e); }
    }
    else { console.error(responseObj.error);}
});

همونطور که میبینید، کدها خیلی پیچیده هستند و به همین دلیل به callback hell یا جهنم callback معروف هستند و خیلی گیج کننده هستند. فرض کنید که شما بخواید بصورت همزمان اطلاعات چند url رو با استفاده از تابع fetch لود کنید. پیاده سازی این کار با callback به مراتب پیچیده‌تر میشه و واقعا آدم رو گیج میکنه.

اینجا هست که Promise‌ها نقش خودشون رو نشون میدن. در جلسه بعد کار با Promise رو به شما آموزش میدیم.

موفق و پیروز باشید.

یا علی

چه امتیازی به این مقاله می دید؟
نویسنده محمد اسفندیاری
بسیار به طراحی وب علاقمندم و به سرعت در حال یادگیری تمام مباحث پیشرفته هستم و دوست دارم که به دیگران هم یاد بدهم.

جلسات دوره

نظرات کاربران

mohammadbrzbrz72

با عرض سلام
ممنون از توضیحاتتون
لطفا این قسمت غلط املاییش رو بگیرین ممنون reques.status ..باید نوشته شه: request.status

نیاز به لاگین

برای ارسال دیدگاه و یا پرسیدن سوال خود در این قسمت، باید در سایت لاگین شوید.