الفرق بين المراجعتين ل"JavaScript/Promise"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
(إنشاء الصفحة. هذه الصفحة من مساهمات عبد اللطيف ايمش)
 
 
(7 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة)
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE:الكائن <code>Promise</code> في JavaScript)}}</noinclude>
+
<noinclude>{{DISPLAYTITLE:الكائن <code>Promise</code> في JavaScript}}</noinclude>
 
يُمثِّل الكائن <code>Promise</code> إكمال (أو فشل) عملية غير متزامنة (asynchronous operation)، والنتيجة المعادة منها.
 
يُمثِّل الكائن <code>Promise</code> إكمال (أو فشل) عملية غير متزامنة (asynchronous operation)، والنتيجة المعادة منها.
  
'''ملاحظة''': هذه الصفحة تشرح الدالة البانية <code>Promise</code> والدوال والخاصيات التابعة لتلك الكائنات. لتعلّم المزيد عن طريقة عمل الوعود (promises) وكيف يمكنك استخدامها، فننصحك بقراءة الصفحة «استخدام الوعود» أولًا. تُستخدَم الدالة البانية بشكل رئيسي لتغليف الدوال التي لا تدعم الوعود.
+
'''ملاحظة''': هذه الصفحة تشرح الدالة البانية <code>Promise</code> والدوال والخاصيات التابعة لتلك الكائنات. لتعلّم المزيد عن طريقة عمل الوعود (promises) وكيف يمكنك استخدامها، فننصحك بقراءة الصفحة «<nowiki/>[[JavaScript/Promise/Using promises|استخدام الوعود]]» أولًا. تُستخدَم الدالة البانية بشكل رئيسي لتغليف الدوال التي لا تدعم الوعود.
  
 
إليك مثال عن استخدام الدالة البانية للكائن <code>Promise</code> لإنشاء وعد بسيط:<syntaxhighlight lang="javascript">
 
إليك مثال عن استخدام الدالة البانية للكائن <code>Promise</code> لإنشاء وعد بسيط:<syntaxhighlight lang="javascript">
سطر 34: سطر 34:
 
الدالة <code>executor</code> ستُنفَّذ مباشرةً من آلية تنفيذ الوعود في المتصفح، مع تمرير الدوال <code>resolve</code> و <code>reject</code> إليها (ستُستدعى الدالة <code>executor</code> مباشرةً قبل أن تعيد الدالة البانية <code>Promise</code> كائنًا).
 
الدالة <code>executor</code> ستُنفَّذ مباشرةً من آلية تنفيذ الوعود في المتصفح، مع تمرير الدوال <code>resolve</code> و <code>reject</code> إليها (ستُستدعى الدالة <code>executor</code> مباشرةً قبل أن تعيد الدالة البانية <code>Promise</code> كائنًا).
  
عند استدعاء الدالة <code>resolve</code> و <code>reject</code> ستقبل (resolve) أو ترفض (reject) الوعد على التوالي وبالترتيب.
+
عند استدعاء الدالة [[JavaScript/Promise/resolve|<code>()resolve</code>]] أو [[JavaScript/Promise/reject|<code>()reject</code>]]، سيُقبَل (resolve) أو يُرفَض (reject) الوعد على التوالي وبالترتيب.
  
ستضم الدالة <code>executor</code> عادةً بعض العمليات غير المتزامنة، وبعد أن تنتهي من عملها فإما أن تستدعي الدالة <code>resolve</code> لقبول الوعد، أو <code>reject</code> إذا حدث خطأ.
+
ستضم الدالة <code>executor</code> عادةً بعض العمليات غير المتزامنة، وبعد أن تنتهي من عملها فإمَّا أن تستدعي الدالة [[JavaScript/Promise/resolve|<code>()resolve</code>]] لقبول الوعد، أو [[JavaScript/Promise/reject|<code>()reject</code>]] إذا حدث خطأ.
  
 
إذا رُمي خطأٌ في الدالة <code>executor</code>، فسيُرفضَ الوعد، وسيتم تجاهل القيمة المُعادة من الدالة <code>executor</code>.
 
إذا رُمي خطأٌ في الدالة <code>executor</code>، فسيُرفضَ الوعد، وسيتم تجاهل القيمة المُعادة من الدالة <code>executor</code>.
سطر 44: سطر 44:
  
 
يكون الكائن <code>Promise</code> في إحدى الحالات الآتية:
 
يكون الكائن <code>Promise</code> في إحدى الحالات الآتية:
* pending (في الانتظار): الحالة المبدئية، أي لم يُحقَّق الوعد أو يُرفَض.
+
* pending (قيد الانتظار): الحالة المبدئية، أي لم يُحقَّق الوعد أو يُرفَض.
 
* fulfilled (محقق): يعني أنَّ العملية قد أُكمِلَت بنجاح.
 
* fulfilled (محقق): يعني أنَّ العملية قد أُكمِلَت بنجاح.
 
* rejected (مرفوض): يعني أنَّ العملية فشلت.
 
* rejected (مرفوض): يعني أنَّ العملية فشلت.
الوعد الذي «في الانتظار» يمكن أن يكون «محققًا» ويعيد قيمةً، أو «مرفوضًا» مع سبب (خطأ). عند حدوث أحد الخيارين السابقين، فستُستدعى إحدى دوال المعالجة باستخدام الدالة <code>[[JavaScript/Promise/then|then]]</code> التابعة للكائن <code>Promise</code>.
+
* settled (مستقر): وهي عكس الحالة pending (قيد الانتظار) أي أن حالة الوعد قد استقرت إلى إحدى الحالتين: إمَّا fulfilled (محقق)، أو rejected (مرفوض).
 +
الوعد الذي «قيد الانتظار» يمكن أن يكون «محققًا» ويعيد قيمةً، أو «مرفوضًا» مع سبب (خطأ). عند حدوث أحد الخيارين السابقين، فستُستدعى إحدى دوال المعالجة باستخدام الدالة <code>[[JavaScript/Promise/then|then]]</code> التابعة للكائن <code>Promise</code>.
  
 
إذا كان الوعد محققًا أو مرفوضًا عند ربط دالة المعالجة معه، فستستدعى دالة المعالجة، لذا لن تحدث «حالة سباق» (race condition) بين إكمال العملية غير المتزامنة، وبين دوال المعالجة التي يجري ربطها مع الوعد.
 
إذا كان الوعد محققًا أو مرفوضًا عند ربط دالة المعالجة معه، فستستدعى دالة المعالجة، لذا لن تحدث «حالة سباق» (race condition) بين إكمال العملية غير المتزامنة، وبين دوال المعالجة التي يجري ربطها مع الوعد.
سطر 53: سطر 54:
 
لمّا كانت الدالتان <code>[[JavaScript/Promise/then|Promise.prototype.then()‎]]</code> و <code>[[JavaScript/Promise/catch|Promise.prototype.catch()‎]]</code> تعيدان بدورهما وعودًا، فيمكن استخدامهما في سلسلة.
 
لمّا كانت الدالتان <code>[[JavaScript/Promise/then|Promise.prototype.then()‎]]</code> و <code>[[JavaScript/Promise/catch|Promise.prototype.catch()‎]]</code> تعيدان بدورهما وعودًا، فيمكن استخدامهما في سلسلة.
  
[صورة]
+
[[ملف:promises.png|بديل=صورة توضيحية عن سَلسَلة عدة وعود مع بعضها بعضًا.|صورة توضيحية عن سَلسَلة عدة وعود مع بعضها بعضًا.|مركز|إطار]]
  
'''ملاحظة''': تملك بعض لغات البرمجة الأخرى آليات لتأخير تقييم قيمة تعبير أو تأجيل عملية حسابية، والتي تسمى عندها «بالوعود» (مثل Scheme). أما الوعود في JavaScript تُمثِّل العمليات التي تحدث فعلًا، والتي يمكن ربطها مع دوال رد النداء (callback functions). إذا كنتَ تبحث عن طريقة لتأخير تقييم قيمة تعبير، ففكر باستخدام [[JavaScript/Arrow Functions|الدوال السهمية]] دون وسائط كما في <code>f = () => expression</code> لتأخير تقييم قيمة التعبير، واستخدام <code>f()‎</code> لتقييم قيمته.
+
'''ملاحظة''': تملك بعض لغات البرمجة الأخرى آليات لتأخير تقييم قيمة تعبير أو تأجيل عملية حسابية، والتي تسمى عندها «بالوعود» (مثل Scheme). أما الوعود في [[JavaScript]] تُمثِّل العمليات التي تحدث فعلًا، والتي يمكن ربطها مع دوال رد النداء (callback functions). إذا كنتَ تبحث عن طريقة لتأخير تقييم قيمة تعبير، ففكر باستخدام [[JavaScript/Arrow Functions|الدوال السهمية]] دون وسائط كما في <code>f = () => expression</code> لتأخير تقييم قيمة التعبير، واستخدام <code>f()‎</code> لتقييم قيمته.
  
 
== الخاصيات ==
 
== الخاصيات ==
سطر 65: سطر 66:
 
تُمثِّل هذه الخاصية سلسلة <code>prototype</code> للدالة البانية <code>Promise</code>.
 
تُمثِّل هذه الخاصية سلسلة <code>prototype</code> للدالة البانية <code>Promise</code>.
  
== التوابع ==
+
== الدوال ==
<code>[[JavaScript/Promise/all|Promise.all(iterable)‎]]</code>
 
  
تعيد وعدًا الذي يمكن أن يتحقق (fulfills) عندما تكون جميع الوعود في الوسيط <code>iterable</code> محققةً، أو يُرفَض (rejects) عند حدوث أول رفض لأحد الوعود الموجودة في الوسيط <code>iterable</code>.
+
=== <code>[[JavaScript/Promise/all|Promise.all(iterable)‎]]</code> ===
 +
تعيد وعدًا يمكن أن يتحقق (fulfills) عندما تكون جميع الوعود في الوسيط <code>iterable</code> محققةً، أو يُرفَض (rejects) عند حدوث أول رفض لأحد الوعود الموجودة في الوسيط <code>iterable</code>.
  
إذا تحققت الوعود في هذه الدالة، فستحقق هذه الدالة مع إعادة مصفوفة فيها قيم الوعود المحققة في نفس ترتيب تعريفها في الوسيط <code>iterable</code>. أما إذا رُفضِ أحد الوعود، فستُرفَض هذه الدالة مع سبب رفض أول وعد مُعرَّف في الوسيط <code>iterable</code>. يمكن الاستفادة من هذه الدالة في تجميع نتائج عدّة وعود معًا.
+
إذا تحققت الوعود في هذه الدالة، فستتحقق هذه الدالة مع إعادة مصفوفة فيها قيم الوعود المحققة في نفس ترتيب تعريفها في الوسيط <code>iterable</code>. أما إذا رُفضِ أحد الوعود، فستُرفَض هذه الدالة مع سبب رفض أول وعد مُعرَّف في الوسيط <code>iterable</code>. يمكن الاستفادة من هذه الدالة في تجميع نتائج عدّة وعود معًا.
  
<code>[[JavaScript/Promise/race|Promise.race(iterable)‎]]</code>
+
=== <code>[[JavaScript/Promise/race|Promise.race(iterable)‎]]</code> ===
 
+
تعيد وعدًا إما أن يُحقَّق أو يُرفَض عند قبول أو رفض واحد من الوعود الموجودة في <code>iterable</code>، مع إعادة القيمة أو السبب من ذاك الوعد.
تعيد وعدًا الذي إما أن يُحقَّق أو يُرفَض عند قبول أو رفض واحد من الوعود الموجودة في <code>iterable</code>، مع إعادة القيمة أو السبب من ذاك الوعد.
 
 
 
<code>[[JavaScript/Promise/reject|Promise.reject(reason)‎]]</code>
 
  
 +
=== <code>[[JavaScript/Promise/reject|Promise.reject(reason)‎]]</code> ===
 
تعيد كائن <code>Promise</code> مرفوض، مع تحديد سبب (reason) الرفض.
 
تعيد كائن <code>Promise</code> مرفوض، مع تحديد سبب (reason) الرفض.
  
<code>[[JavaScript/Promise/resolve|Promise.resolve(value)‎]]</code>
+
=== <code>[[JavaScript/Promise/resolve|Promise.resolve(value)‎]]</code> ===
 
+
تعيد كائن <code>Promise</code> مقبول مع القيمة (value) المحددة. إذا ارتبطت هذه القيمة بالدالة [[JavaScript/Promise/then|<code>()then</code>]]، فسيتّبع (follow) الوعد المعاد تلك الدالة المرتبطة بالدالة [[JavaScript/Promise/then|<code>()then</code>]]، أو سيكون الوعد المُعاد محققًا مع القيمة <code>value</code>.
تعيد كائن <code>Promise</code> مقبول مع القيمة (value) المحددة. إذا ارتبطت هذه القيمة بالدالة <code>then</code>، فسيتّبع (follow) الوعد المعاد تلك الدالة المرتبطة بالدالة <code>then</code>، أو سيكون الوعد المُعاد محققًا مع القيمة <code>value</code>.
 
  
 
إذا لم تكن تعرف إذا كانت القيمة <code>value</code> وعدًا أم لا، فاستخدم الدالة <code>[[JavaScript/Promise/resolve|Promise.resolve(value)‎]]</code> عليها، وتعامل مع القيمة المُعادة كوعد.
 
إذا لم تكن تعرف إذا كانت القيمة <code>value</code> وعدًا أم لا، فاستخدم الدالة <code>[[JavaScript/Promise/resolve|Promise.resolve(value)‎]]</code> عليها، وتعامل مع القيمة المُعادة كوعد.
سطر 94: سطر 92:
  
 
=== الدوال ===
 
=== الدوال ===
<code>[[JavaScript/Promise/prototype/catch|Promise.prototype.catch(onRejected)‎]]</code>
 
  
 +
==== <code>[[JavaScript/Promise/catch|Promise.prototype.catch(onRejected)‎]]</code> ====
 
تضيف دالة رد نداء (callback) للتعامل مع حالة رفض (rejection) للوعد، وتعيد وعدًا جديدًا يُقبَل (resolve) إلى القيمة المعادة من دالة رد النداء إذا اُستدعيت، أو إلى قيمة الوعد المحقق إذا تحقق الوعد بدلًا من رفضه.
 
تضيف دالة رد نداء (callback) للتعامل مع حالة رفض (rejection) للوعد، وتعيد وعدًا جديدًا يُقبَل (resolve) إلى القيمة المعادة من دالة رد النداء إذا اُستدعيت، أو إلى قيمة الوعد المحقق إذا تحقق الوعد بدلًا من رفضه.
  
<code>[[JavaScript/Promise/prototype/then|Promise.prototype.then(onFulfilled, onRejected)‎]]</code>
+
==== <code>[[JavaScript/Promise/then|Promise.prototype.then(onFulfilled, onRejected)‎]]</code> ====
 
 
 
تضيف دوالًا لمعالجة حالة التحقيق والرفض لوعدٍ ما، وتعيد وعدًا جديدًا يُقبَل إلى القيمة المعادة من دالة المعالجة، أو لإلى القيمة الأصلية للوعد إذا لم يُعالَج (أي أنَّ الوسيط <code>onFulfilled</code> أو <code>onRejected</code> لم يكن دالةً).
 
تضيف دوالًا لمعالجة حالة التحقيق والرفض لوعدٍ ما، وتعيد وعدًا جديدًا يُقبَل إلى القيمة المعادة من دالة المعالجة، أو لإلى القيمة الأصلية للوعد إذا لم يُعالَج (أي أنَّ الوسيط <code>onFulfilled</code> أو <code>onRejected</code> لم يكن دالةً).
  
<code>[[JavaScript/Promise/prototype/finally|Promise.prototype.finally(onFinally)‎]]</code>
+
==== <code>[[JavaScript/Promise/finally|Promise.prototype.finally(onFinally)‎]]</code> ====
 
 
 
تضيف دالة معالجة إلى الوعد، وتعيد وعدًا جديدًا يقبل (resolve) عندما يُقبَل الوعد الأصلي. وستُستدعى دالة المعالجة <code>onFinally</code> عند انتهاء تنفيذ الوعد، سواءً تحقق أو رفض.
 
تضيف دالة معالجة إلى الوعد، وتعيد وعدًا جديدًا يقبل (resolve) عندما يُقبَل الوعد الأصلي. وستُستدعى دالة المعالجة <code>onFinally</code> عند انتهاء تنفيذ الوعد، سواءً تحقق أو رفض.
  
سطر 132: سطر 128:
 
سنستدعي الدالة <code>[[JavaScript/Promise/resolve|resolve()‎]]</code> عند نجاح تنفيذ المهمة غير المتزامنة، والدالة <code>[[JavaScript/Promise/reject|reject()‎]]</code> عند فشل تنفيذ تلك المهمة.
 
سنستدعي الدالة <code>[[JavaScript/Promise/resolve|resolve()‎]]</code> عند نجاح تنفيذ المهمة غير المتزامنة، والدالة <code>[[JavaScript/Promise/reject|reject()‎]]</code> عند فشل تنفيذ تلك المهمة.
  
سنستخدم في المثال الآتي الدالة <code>[[JavaScript/setTimeout|setTimeout()‎]]</code> لمحاكاة شيفرة غير متزامنة. في الواقع، ستستخدم شيئًا يشبه تقنية Ajax (أي الكائن XHR) أو الواجهة البرمجية للغة [[HTML|HTML5]].
+
سنستخدم في المثال الآتي الدالة <code>[[JavaScript/setTimeout|setTimeout()‎]]</code> لمحاكاة شيفرة غير متزامنة. في الواقع، ستستخدم شيئًا يشبه تقنية Ajax (أي الكائن <code>XHR</code>) أو الواجهة البرمجية للغة [[HTML|HTML5]].
  
ثم سنستخدم الدالة <code>[[JavaScript/Promise/prototype/then|then()‎]]</code> لمعالجة القيمة المعادة من الوعد، وستكون قيمة المعامل <code>successMessage</code> مساويةً للسلسلة النصية التي مررناها للدالة [[JavaScript/Promise/resolve|<code>resolve()‎</code>]]:<syntaxhighlight lang="javascript">
+
ثم سنستخدم الدالة <code>[[JavaScript/Promise/then|then()‎]]</code> لمعالجة القيمة المعادة من الوعد، وستكون قيمة المعامل <code>successMessage</code> مساويةً للسلسلة النصية التي مررناها للدالة [[JavaScript/Promise/resolve|<code>resolve()‎</code>]]:<syntaxhighlight lang="javascript">
 
let myFirstPromise = new Promise((resolve, reject) => {
 
let myFirstPromise = new Promise((resolve, reject) => {
  
سطر 151: سطر 147:
 
هذا المثال الصغير يبيّن آلية عمل الكائن <code>Promise</code>. ستُستدعى الدالة <code>testPromise()‎</code> في كل مرة يُضغط فيها على العنصر <code>[[HTML/button|<button>]]</code>، إذ سيُنشَأ وعد التي سيتحقق ويعيد عدد الوعود (العدّ يبدأ من 1) كل 1-3 ثانية (عشوائيًا) باستخدام الدالة <code>[[JavaScript/setTimeout|setTimeout()‎]]</code>. تُستخدَم الدالة البانية <code>Promise()‎</code> لإنشاء ذاك الوعد.
 
هذا المثال الصغير يبيّن آلية عمل الكائن <code>Promise</code>. ستُستدعى الدالة <code>testPromise()‎</code> في كل مرة يُضغط فيها على العنصر <code>[[HTML/button|<button>]]</code>، إذ سيُنشَأ وعد التي سيتحقق ويعيد عدد الوعود (العدّ يبدأ من 1) كل 1-3 ثانية (عشوائيًا) باستخدام الدالة <code>[[JavaScript/setTimeout|setTimeout()‎]]</code>. تُستخدَم الدالة البانية <code>Promise()‎</code> لإنشاء ذاك الوعد.
  
سنسجِّل تحقق الوعد في كل مرة، باستخدام الدالة [[JavaScript/Promise/prototype/then|<code>then()‎</code>]]. وستكون هنالك سجلات تُظهِر كيف يمكن الدمج بين الشيفرة المتزامنة في الدالة مع إكمال الوعد في الشيفرة غير المتزامنة:<syntaxhighlight lang="javascript">
+
سنسجِّل تحقق الوعد في كل مرة، باستخدام الدالة <code>[[JavaScript/Promise/then|then()‎]]</code>. وستكون هنالك سجلات تُظهِر كيف يمكن الدمج بين الشيفرة المتزامنة في الدالة مع إكمال الوعد في الشيفرة غير المتزامنة:<syntaxhighlight lang="javascript">
 
'use strict';
 
'use strict';
 
var promiseCount = 0;
 
var promiseCount = 0;
سطر 195: سطر 191:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
== دعم المتصفحات ==
 +
{| class="wikitable"
 +
!الميزة
 +
!Chrome
 +
!Firefox
 +
!Internet Explorer
 +
!Opera
 +
!Safari
 +
|-
 +
!الدعم الأساسي
 +
|32
 +
|29
 +
|غير مدعوم
 +
|19
 +
|8
 +
|-
 +
!الباني (<code>Promise()‎</code>)
 +
|32
 +
|29 *
 +
|غير مدعوم
 +
|19
 +
|8 **
 +
|-
 +
!<code>[[JavaScript/Promise/all|all]]</code>
 +
|32
 +
|29
 +
|غير مدعوم
 +
|19
 +
|8
 +
|-
 +
!<code>[[JavaScript/Promise/prototype|prototype]]</code>
 +
|32
 +
|29
 +
|غير مدعوم
 +
|19
 +
|8
 +
|-
 +
!<code>[[JavaScript/Promise/catch|catch]]</code>
 +
|32
 +
|29
 +
|غير مدعوم
 +
|19
 +
|8
 +
|-
 +
!<code>[[JavaScript/Promise/finally|finally]]</code>
 +
|63
 +
|58
 +
|غير مدعوم
 +
|50
 +
|11.1
 +
|-
 +
!<code>[[JavaScript/Promise/then|then]]</code>
 +
|32
 +
|29
 +
|غير مدعوم
 +
|19
 +
|8
 +
|-
 +
!<code>[[JavaScript/Promise/race|race]]</code>
 +
|32
 +
|29
 +
|غير مدعوم
 +
|19
 +
|8
 +
|-
 +
!<code>[[JavaScript/Promise/reject|reject]]</code>
 +
|32
 +
|29
 +
|غير مدعوم
 +
|19
 +
|8
 +
|-
 +
!<code>[[JavaScript/Promise/resolve|resolve]]</code>
 +
|32
 +
|29
 +
|غير مدعوم
 +
|19
 +
|8
 +
|}
 +
<nowiki>*</nowiki> أصبح الباني يتطلب استعمال المعامل <code>new</code> معه بدءًا من الإصدار 37.
 +
 +
<nowiki>**</nowiki> أصبح الباني يتطلب استعمال المعامل <code>new</code> معه بدءًا من الإصدار 10.
  
 
== المصادر ==
 
== المصادر ==
 
* [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise صفحة Promise في توثيق MDN الرسمي].
 
* [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise صفحة Promise في توثيق MDN الرسمي].
 
[[تصنيف:JavaScript]]
 
[[تصنيف:JavaScript]]
[[تصنيف:JavaScript Object]]
+
[[تصنيف:JavaScript Global Objects]]
 +
[[تصنيف:JavaScript Promise]]

المراجعة الحالية بتاريخ 06:40، 20 أبريل 2019

يُمثِّل الكائن Promise إكمال (أو فشل) عملية غير متزامنة (asynchronous operation)، والنتيجة المعادة منها.

ملاحظة: هذه الصفحة تشرح الدالة البانية Promise والدوال والخاصيات التابعة لتلك الكائنات. لتعلّم المزيد عن طريقة عمل الوعود (promises) وكيف يمكنك استخدامها، فننصحك بقراءة الصفحة «استخدام الوعود» أولًا. تُستخدَم الدالة البانية بشكل رئيسي لتغليف الدوال التي لا تدعم الوعود.

إليك مثال عن استخدام الدالة البانية للكائن Promise لإنشاء وعد بسيط:

var promise1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve('foo');
  }, 300);
});

promise1.then(function(value) {
  console.log(value);
  // "foo" الناتج المتوقع
});

console.log(promise1);
// [object Promise] الناتج المتوقع

البنية العامة

new Promise(executor /*function(resolve, reject) { ... }  */);

المعاملات

executor

الدالة التي ستُمرَّر إلى الدالة البانية والتي لها وسيطين هما resolve و reject.

الدالة executor ستُنفَّذ مباشرةً من آلية تنفيذ الوعود في المتصفح، مع تمرير الدوال resolve و reject إليها (ستُستدعى الدالة executor مباشرةً قبل أن تعيد الدالة البانية Promise كائنًا).

عند استدعاء الدالة ()resolve أو ()reject، سيُقبَل (resolve) أو يُرفَض (reject) الوعد على التوالي وبالترتيب.

ستضم الدالة executor عادةً بعض العمليات غير المتزامنة، وبعد أن تنتهي من عملها فإمَّا أن تستدعي الدالة ()resolve لقبول الوعد، أو ()reject إذا حدث خطأ.

إذا رُمي خطأٌ في الدالة executor، فسيُرفضَ الوعد، وسيتم تجاهل القيمة المُعادة من الدالة executor.

الوصف

الكائن Promise هو كائنٌ وسيط (proxy) لقيمةٍ غير معروفة تحديدًا عند إنشاء الوعد، مما يسمح لنا بربط دوال لمعالجة الأحداث غير المتزامنة التي تكون نهايتها النجاح أو الفشل. وهذا يسمح للدوال غير المتزامنة (asynchronous) أن تعيد قيمًا مثلها كمثل الدوال المتزامنة؛ لكن بدلًا من إعادة القيمة النهائية مباشرةً، فإنَّ الدوال غير المتزامنة تعيد «وعدًا» بتوفير القيمة في مرحلة ما من المستقبل.

يكون الكائن Promise في إحدى الحالات الآتية:

  • pending (قيد الانتظار): الحالة المبدئية، أي لم يُحقَّق الوعد أو يُرفَض.
  • fulfilled (محقق): يعني أنَّ العملية قد أُكمِلَت بنجاح.
  • rejected (مرفوض): يعني أنَّ العملية فشلت.
  • settled (مستقر): وهي عكس الحالة pending (قيد الانتظار) أي أن حالة الوعد قد استقرت إلى إحدى الحالتين: إمَّا fulfilled (محقق)، أو rejected (مرفوض).

الوعد الذي «قيد الانتظار» يمكن أن يكون «محققًا» ويعيد قيمةً، أو «مرفوضًا» مع سبب (خطأ). عند حدوث أحد الخيارين السابقين، فستُستدعى إحدى دوال المعالجة باستخدام الدالة then التابعة للكائن Promise.

إذا كان الوعد محققًا أو مرفوضًا عند ربط دالة المعالجة معه، فستستدعى دالة المعالجة، لذا لن تحدث «حالة سباق» (race condition) بين إكمال العملية غير المتزامنة، وبين دوال المعالجة التي يجري ربطها مع الوعد.

لمّا كانت الدالتان Promise.prototype.then()‎ و Promise.prototype.catch()‎ تعيدان بدورهما وعودًا، فيمكن استخدامهما في سلسلة.

صورة توضيحية عن سَلسَلة عدة وعود مع بعضها بعضًا.
صورة توضيحية عن سَلسَلة عدة وعود مع بعضها بعضًا.

ملاحظة: تملك بعض لغات البرمجة الأخرى آليات لتأخير تقييم قيمة تعبير أو تأجيل عملية حسابية، والتي تسمى عندها «بالوعود» (مثل Scheme). أما الوعود في JavaScript تُمثِّل العمليات التي تحدث فعلًا، والتي يمكن ربطها مع دوال رد النداء (callback functions). إذا كنتَ تبحث عن طريقة لتأخير تقييم قيمة تعبير، ففكر باستخدام الدوال السهمية دون وسائط كما في f = () => expression لتأخير تقييم قيمة التعبير، واستخدام f()‎ لتقييم قيمته.

الخاصيات

Promise.length

قيمة الخاصية length تساوي 1 دومًا، وهو عدد وسائط الدالة البانية.

Promise.prototype

تُمثِّل هذه الخاصية سلسلة prototype للدالة البانية Promise.

الدوال

Promise.all(iterable)‎

تعيد وعدًا يمكن أن يتحقق (fulfills) عندما تكون جميع الوعود في الوسيط iterable محققةً، أو يُرفَض (rejects) عند حدوث أول رفض لأحد الوعود الموجودة في الوسيط iterable.

إذا تحققت الوعود في هذه الدالة، فستتحقق هذه الدالة مع إعادة مصفوفة فيها قيم الوعود المحققة في نفس ترتيب تعريفها في الوسيط iterable. أما إذا رُفضِ أحد الوعود، فستُرفَض هذه الدالة مع سبب رفض أول وعد مُعرَّف في الوسيط iterable. يمكن الاستفادة من هذه الدالة في تجميع نتائج عدّة وعود معًا.

Promise.race(iterable)‎

تعيد وعدًا إما أن يُحقَّق أو يُرفَض عند قبول أو رفض واحد من الوعود الموجودة في iterable، مع إعادة القيمة أو السبب من ذاك الوعد.

Promise.reject(reason)‎

تعيد كائن Promise مرفوض، مع تحديد سبب (reason) الرفض.

Promise.resolve(value)‎

تعيد كائن Promise مقبول مع القيمة (value) المحددة. إذا ارتبطت هذه القيمة بالدالة ()then، فسيتّبع (follow) الوعد المعاد تلك الدالة المرتبطة بالدالة ()then، أو سيكون الوعد المُعاد محققًا مع القيمة value.

إذا لم تكن تعرف إذا كانت القيمة value وعدًا أم لا، فاستخدم الدالة Promise.resolve(value)‎ عليها، وتعامل مع القيمة المُعادة كوعد.

Promise prototype

الخاصيات

Promise.prototype.constructor

تعيد الدالة التي تُنشِئ نسخةً من الكائن Promise، وهي الدالة البانية.

الدوال

Promise.prototype.catch(onRejected)‎

تضيف دالة رد نداء (callback) للتعامل مع حالة رفض (rejection) للوعد، وتعيد وعدًا جديدًا يُقبَل (resolve) إلى القيمة المعادة من دالة رد النداء إذا اُستدعيت، أو إلى قيمة الوعد المحقق إذا تحقق الوعد بدلًا من رفضه.

Promise.prototype.then(onFulfilled, onRejected)‎

تضيف دوالًا لمعالجة حالة التحقيق والرفض لوعدٍ ما، وتعيد وعدًا جديدًا يُقبَل إلى القيمة المعادة من دالة المعالجة، أو لإلى القيمة الأصلية للوعد إذا لم يُعالَج (أي أنَّ الوسيط onFulfilled أو onRejected لم يكن دالةً).

Promise.prototype.finally(onFinally)‎

تضيف دالة معالجة إلى الوعد، وتعيد وعدًا جديدًا يقبل (resolve) عندما يُقبَل الوعد الأصلي. وستُستدعى دالة المعالجة onFinally عند انتهاء تنفيذ الوعد، سواءً تحقق أو رفض.

إنشاء وعد

يمكن إنشاء كائن Promise عن طريق الكلمة المفتاحية new والدالة البانية الخاصة به. هذه الدالة البانية تأخذ وسيطًا هو دالة تسمى «الدالة المنفذة» (executor function). ويجب أن تأخذ هذه الدالة دالتين كمعاملين، أولهما (resolve) ستستدعى عندما تكتمل المهمة غير المتزامنة بنجاح وتُعيد نتائج المهمة كقيمة، أما الدالة الثانية (reject) فستستدعى عند فشل المهمة، وتعيد سبب الفشل، ويكون عادةً كائن الخطأ.

const myFirstPromise = new Promise((resolve, reject) => {
  // القيام بعملية غير متزامنة حتى استدعاء دالة:
  //
  //   resolve(someValue);       => القبول
  // أو
  //   reject("failure reason"); => الرفض
});

لتوفير دالة لها إمكانيات الوعود، فاجعلها تعيد وعدًا:

function myAsyncFunction(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
  });
}

أمثلة

مثال بسيط

سنستدعي الدالة resolve()‎ عند نجاح تنفيذ المهمة غير المتزامنة، والدالة reject()‎ عند فشل تنفيذ تلك المهمة.

سنستخدم في المثال الآتي الدالة setTimeout()‎ لمحاكاة شيفرة غير متزامنة. في الواقع، ستستخدم شيئًا يشبه تقنية Ajax (أي الكائن XHR) أو الواجهة البرمجية للغة HTML5.

ثم سنستخدم الدالة then()‎ لمعالجة القيمة المعادة من الوعد، وستكون قيمة المعامل successMessage مساويةً للسلسلة النصية التي مررناها للدالة resolve()‎:

let myFirstPromise = new Promise((resolve, reject) => {

  setTimeout(function(){
    resolve("Success!"); // كل شيءٍ جرى على ما يرام
  }, 250);
});

myFirstPromise.then((successMessage) => {

  console.log("Yay! " + successMessage);
});

مثال متقدم

هذا المثال الصغير يبيّن آلية عمل الكائن Promise. ستُستدعى الدالة testPromise()‎ في كل مرة يُضغط فيها على العنصر <button>، إذ سيُنشَأ وعد التي سيتحقق ويعيد عدد الوعود (العدّ يبدأ من 1) كل 1-3 ثانية (عشوائيًا) باستخدام الدالة setTimeout()‎. تُستخدَم الدالة البانية Promise()‎ لإنشاء ذاك الوعد.

سنسجِّل تحقق الوعد في كل مرة، باستخدام الدالة then()‎. وستكون هنالك سجلات تُظهِر كيف يمكن الدمج بين الشيفرة المتزامنة في الدالة مع إكمال الوعد في الشيفرة غير المتزامنة:

'use strict';
var promiseCount = 0;

function testPromise() {
    let thisPromiseCount = ++promiseCount;

    let log = document.getElementById('log');
    log.insertAdjacentHTML('beforeend', thisPromiseCount +
        ') Started (<small>Sync code started</small>)<br/>');

    // سنُنشِئ وعدًا جديدًا
    let p1 = new Promise(
        // هذه الدالة قادرة على تحقيق أو رفض الوعد
        // reject the promise
       (resolve, reject) => {
            log.insertAdjacentHTML('beforeend', thisPromiseCount +
                ') Promise started (<small>Async code started</small>)<br/>');
            // هذا مثال بسيط عن إنشاء عدم تزامن
            window.setTimeout(
                function() {
                    // حققنا الوعد
                    resolve(thisPromiseCount);
                }, Math.random() * 2000 + 1000);
        }
    );

    // then سنُعرِّف ماذا سيحدث عند قبول الوعد باستخدام 
    // catch وسنعرف ماذا سيحدث عند رفض الوعد باستخدام 
    p1.then(
        // تسجيل القيمة
        function(val) {
            log.insertAdjacentHTML('beforeend', val +
                ') Promise fulfilled (<small>Async code terminated</small>)<br/>');
        }).catch(
        // تسجيل سبب الرفض
       (reason) => {
            console.log('Handle rejected promise ('+reason+') here.');
        });

    log.insertAdjacentHTML('beforeend', thisPromiseCount +
        ') Promise made (<small>Sync code terminated</small>)<br/>');
}

دعم المتصفحات

الميزة Chrome Firefox Internet Explorer Opera Safari
الدعم الأساسي 32 29 غير مدعوم 19 8
الباني (Promise()‎) 32 29 * غير مدعوم 19 8 **
all 32 29 غير مدعوم 19 8
prototype 32 29 غير مدعوم 19 8
catch 32 29 غير مدعوم 19 8
finally 63 58 غير مدعوم 50 11.1
then 32 29 غير مدعوم 19 8
race 32 29 غير مدعوم 19 8
reject 32 29 غير مدعوم 19 8
resolve 32 29 غير مدعوم 19 8

* أصبح الباني يتطلب استعمال المعامل new معه بدءًا من الإصدار 37.

** أصبح الباني يتطلب استعمال المعامل new معه بدءًا من الإصدار 10.

المصادر