JavaScript threading


السلام عليكم و رحمه الله تعالى و بركاته

مقدمه
انشاء Worker جديد
انهاء عمل worker قديم
بعض القيود المفروضه على worker
الكائن navigator
إستيراد الملفات من داخل ال worker
التعامل مع أخطاء ال worker

مقدمه

تطبيقات الجافاسكربت ذات طبيعه single threaded اى ان التطبيق كله يعمل داخل thread واحد فقط فى ال CPU ، يتم تنفيذ اوامر التطبيق بنظام queue حيث يبدأ تنفيذ السطر الاول ثم الثانى حتى ينتهى التطبيق عند السطر الاخير ، و هذا يؤدى الى ان التطبيقات التى تستهلك كميه كبيره من الذاكره – نتيجه اجراء الكثير من العمليات و الحسابات المعقده -ينتهى بها المطاف إلى تجميد واجهه المستخدم UI freezing او انتهاء التطبيق .
خذ عندك مثلا هذه الوظيفه التى تقوم بحساب fibonacci number ، رقم فيبوناتشى هو مجموع رقمى فيبوناتشى للرقمين الذين يسبقوه مع العلم ان رقم فيبوناتشى ل 0 يساوى 0 ، و رقم فيبوناتشى ل 1 = 1 :

function fibonacci(n){
    if(n==0 || n==1){
        return n;
    } else {
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}

إذا قمت بمحاوله إيجاد رقم فيبوناتشى للرقم 11 فإن الوظيفه fibonacci سوف تستدعى نفسها اكثر من 400 مره وسينتهى الامر إلى تجميد واجهه المستخدم حتى ينتهى من حساب الرقم ، او رساله تخبرك بأن تقوم بإلغاء تنفيذ هذا التطبيق إن قمت بحساب رقم فيبوناتشى لرقم كبير مثل 100 :D .

لكن الامر الان اصبح مختلف بعد تقديم Worker api فى Google geras الذى تم معايرته من قبل WHATWG و تم ادراجه فى متصفح FireFox 3.5 و Safari 4 و Chrome 2 و تطبيقات سطح المكتب التى يتم برمجتها ب AIR 2.0 او titanium و تطبيقات الموبايل التى يتم برمجتها ب titanium mobile و ايضا يمكنك استخدامه فى برمجه امتدادات الفايرفوكس و بإنتظار IE و Opear ، الان تطبيقات الجافاسكربت يمكننها انشاء threads لتقليل الحمل من على ال thread الرئيسى ، حيث يمكنك الان تشغيل ملفات جافاسكربت فى thread خلفى -background thread- لن يؤثر على ال thread الرئيسى ، و يمكن ايضا لل background thread انشاء threads اخرى لتعاونه فى انجاز عمله ، حيث يتم الاتصال بين ال threads المختلفه عن طريق الحدث onmessage و الوظيفه postMessage كما سنرى لاحقا ، يمكن لل threads المختلفه تبادل الرسائل فى صوره نصوص او اعداد او قيم منطقيه او JSON لكن لابد ان لا يحتوى على function او cyclical reference .

انشاء worker جديد

يمكنك انشاء thread خلفى بمنتهى البساطه عن طريق تمرير مسار ملف الجافاسكربت الذى سيعمل فى thread خلفى Worker constructor كما يوضح الكود البسيط التالى :

var myWorker = new Worker("fibbonaci.js");

عن طريق السطر السابق سيعمل ملف fibonacci.js داخل thread منفصل لحساب رقم فيبوناتشى بدون تجميد واجهه المستخدم او التأثير على كفائه ال thread الرئيسى ، و من خلال تسجيل مستمع لحدث onmessage ل myWorker يمكننا تلقى رسائل من ال thread الخاص ب fibonacci.js كما يوضح الكود البسيط التالى :

var myWorker = new Worker("fibbonaci.js");
myWorker.onmessage = function(event){
    alert(event.data);
};

داخل داله مستمع الحدث onmessage الخاصيه data للكائن event تشير إلى البيانات التى يرسلها ال thread الخلفى ، يمكننا ارسال رساله إلى ال thread الخاص ب fibonacci.js عن طريق الوظيفه postMessage كما يوضح الكود البسيط التالى :

var myWorker = new Worker("fibbonaci.js");
myWorker.onmessage = function(event){
    alert(event.data);
};
myWorker.postMessage(11);

السطر الاول فى الكود السابق يقوم بإنشاء thread جديد للملف fibonacci.js ، و السطر الثانى يسجل مستمع لحدث message لتلقى اى رساله يرسلها ال thread الخاص ب fibonacci.js ، اما السطر الرابع و الاخير يقوم بإرسال القيمه 11 إلى ال thread الخاص ب fibonacci.js حتى يقوم بالعمل عليها ، اى حساب رقم فيبوناتشى للرقم 11 فى ال thread منفصل .

الكود داخل fibonacci.js يقوم بالإستماع للحدث message و عندما يتلقى رساله برقم ما ، يقوم بحساب رقم الفيبوناتشى له و ارساله عن طريق الوظيفه postMessage إلى ال thread الرئيسى كما يوضح الكود البسيط التالى :

/* inside fibonacci.js file */
onmessage = function(event){
    var num = parseInt(event.data); // get the message as integer
    var fibNum = fibonacci(num); // get the fibonacci number
    postMessage(fibNum); // post the result to the main thread
}
function fibonacci(n){
    if(n==0 || n==1){
        return n;
    } else {
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}
/* end of fibonacci.js file */

عندما يستقبل رساله يستخرج منها الرقم من خلال event.data ثم يحصل على رقم فيبوناتشى عن تمرير الرقم إلى وظيفه fibonacci و فى النهايه يقوم بإرسال النتيجه إلى ال thread الرئيسى عن طريق postMessage .

القاعده العامه هى ان ال thread يقوم بإرساله رسائل إلى thread اخر عن طريق الوظيفه postMessage و يقوم بإستقبال رسائل ال threads الاخرى من خلال مستمع الحدث onmessage .

إنهاء عمل worker قديم

اذا كنت تريد ايقاف عمل worker تم انشاءه من قبل ، قم بإستدعاء الوظيفه terminate الخاصه بهذا ال worker ، حيث سيتم قتل ال thread الخاص به بدون اكمال عمله مباشره كما يوضح الكود البسيط التالى:

myWorker.terminate(); // close and kill myWorker thread

بعض القيود المفروضه على worker

الكود الذى يعمل فى thread جديد عن طريق worker لايمكنه الوصول إلى ال DOM ، اذا كان هناك تطبيق يقوم بتعديل ال DOM فإن هذه العمليه لابد ان يتولاها ال thread الرئيسى ، ال thread الفرعى عليه العمليات المعقده فقط ، يمكن لل thread الفرعى استخدام ال XMLHttpRequest لإجراء اتصالات اجاكس لكنه لا يستطيع الوصول إلى XMLResponse او channel ، لا يمكن لل thread الفرعى ارسال function او cyclic reference إلى ال thread الرئيسى ، يتم تحويل البيانات تلقائيا إلى صيغه JSON بعد تنقيحها ، و يمكنك ايضا استخدام setTimeout و clearTimeout و setInterval و clearInterval .

الكائن navigator

يمكنك الوصول إلى الكائن navigator من داخل ال thread الفرعى للحصول على معلومات عن المتصفح ، يحتوى الكائن navigator على اربع خواص :

navigator.appName
navigator.appVersion
navigator.platform
navigator.userAgent

إستيراد الملفات من داخل ال worker

يمكنك اسيراد ملفات الجافاسكربت من داخل ال worker عن طريق استخدام وظيفه imortScripts التى تقبل مسار الملفات التى تريد استيرادها ، يتم تحميل الملفات بأى ترتيب لكن يتم تنفيذها بالترتيب الذى تريد عند تمريرها للوظيفه كما يوضح الكود البسيط التالى :

importScripts(); // imports nothing
importScripts("foo.js"); // imports one file
importScripts("foo.js", "bar.js"); // imports two files

التعامل مع أخطاء ال worker

عندما يحدث خطأ فى ال worker سيتم استدعاء مستمع الحدث الخاص ب onerror المرتبط به و سيتم تمرير لمستمع الحدث الكائن event الذى يحتوى على 3 خصائص تحتوى على معلومات عن الخطأ و هى message و filename و lineno ، يمكن منع الخطأ من خلال الوظيفه preventDefault كما يوضح الكود التالى :

var myWorker = new Worker("worker.js");
myWorker.onerror = function(event){
    event.message; // human readable error message
    event.lineno; // error line number
    event.filename; // file name at which error occurs
    event.preventDefault(); // prevent error propagation
}

للمزيد

هذا ليس كل شىء هناك الكثير من الكائنات لم يغطيها هذا المقال ، مواصفات worker api لن تكتمل و يمكن تغيرها او زياده ميزات اخرى فى المتصفحات ، هناك ايضا بعض الكائنات لم يتم ادراجها مثل SharedWorker و DedicatedWorker و غيره ، يمكنك قراءه مواصفات ال web workers كامله من هنا ، بالإضافه إلى مقاله usinng web workers من موزيلا ، و هذه التدوينه من مدونه mozilla developers center .

About these ads

الأوسمة: , ,

2 تعليقات to “JavaScript threading”

  1. عبدالله Says:

    ما عندي غير كلمة مشكور جداً ^_^

    باركـ الله فيك :)

أضف تعليق

إملأ الحقول أدناه بالمعلومات المناسبة أو إضغط على إحدى الأيقونات لتسجيل الدخول:

WordPress.com Logo

You are commenting using your WordPress.com account. تسجيل الخروج / تغيير )

Twitter picture

You are commenting using your Twitter account. تسجيل الخروج / تغيير )

Facebook photo

You are commenting using your Facebook account. تسجيل الخروج / تغيير )

Google+ photo

You are commenting using your Google+ account. تسجيل الخروج / تغيير )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: