يوم جيد يا هبر! أقدم إليكم ترجمة مقالة
"فهم الوعود في جافا سكريبت" من تأليف سوخيندر أرورا.
من مؤلف الترجمة: وكذلك المؤلف نفسه ، آمل أن تكون المقالة مفيدة لك. من فضلك ، إذا كانت قد ساعدتك حقًا على تعلم شيء جديد لنفسك ، فلا تكون كسولًا جدًا في الذهاب إلى المقالة الأصلية وشكر المؤلف! سأكون سعيدا لملاحظاتك!
رابط لترجمة المقال على جافا سكريبت غير متزامن من نفس المؤلف .JavaScript هي لغة برمجة مفردة ، مما يعني أنه يمكن القيام بشيء واحد في وقت واحد. قبل ES6 ، استخدمنا عمليات الاسترجاعات لإدارة المهام غير المتزامنة ، مثل طلب الشبكة.
باستخدام الوعود ، يمكننا تجنب "رد الاتصال بالجحيم" وجعل كودنا أكثر نظافة ، وأكثر قابلية للقراءة ، وأسهل للفهم.
لنفترض أننا نرغب في الحصول على بعض البيانات من الخادم بشكل غير متزامن ، باستخدام عمليات الاسترجاعات ، سنفعل شيئًا مثل هذا:
getData(function(x){ console.log(x); getMoreData(x, function(y){ console.log(y); getSomeMoreData(y, function(z){ console.log(z); }); }); });
هنا ، أطلب بعض البيانات من الخادم باستخدام دالة
getData () ، والتي تستقبل البيانات داخل وظيفة رد الاتصال. داخل وظيفة رد الاتصال ، أطلب بيانات إضافية عن طريق استدعاء
دالة getMoreData () ، وتمرير البيانات السابقة كوسيطة ، وما إلى ذلك.
هذا هو ما نسميه "الجحيم رد الاتصال" ، حيث يتم تداخل كل رد اتصال داخل الآخر ، ويعتمد كل رد اتصال داخلي على الأصل.
يمكننا إعادة كتابة المقتطف أعلاه باستخدام الوعود:
getData() .then((x) => { console.log(x); return getMoreData(x); }) .then((y) => { console.log(y); return getSomeMoreData(y); }) .then((z) => { console.log(z); });
يمكنك أن ترى ما أصبح أكثر قابلية للقراءة من خلال مثال رد الاتصال الأول.
ما هي الوعود؟
الوعد (الوعد) هو كائن يحتوي على القيمة المستقبلية لعملية غير متزامنة. على سبيل المثال ، إذا طلبت بعض البيانات من الخادم ، وعدنا Promis باستلام هذه البيانات ، والتي يمكننا استخدامها في المستقبل.
قبل الغوص في كل هذه الأشياء التقنية ، دعونا نلقي نظرة على مصطلحات الوعود.
الوعد الدول
الوعد في جافا سكريبت ، مثل الوعد في الحياة الحقيقية ، يحتوي على 3 حالات. يمكن أن يكون هذا 1) غير محلول (معلق) ، 2) حل / حل (مكتمل) أو 3) مرفوض / مرفوض.
غير محلول أو معلق - بروميس ينتظر إذا كانت النتيجة غير جاهزة. بمعنى أنه يتوقع إكمال شيء (على سبيل المثال ، إكمال عملية غير متزامنة).
حل أو مكتمل - حل Promis إذا كانت النتيجة متوفرة. وهذا هو ، أكمل شيء تنفيذه (على سبيل المثال ، عملية غير متزامنة) وكل شيء سار بشكل جيد.
تم الرفض - تم رفض Promis في حالة حدوث خطأ أثناء التنفيذ.
الآن نحن نعرف ما هي Promis ومصطلحاته ، دعنا نعود إلى الجزء العملي من الوعود.
إنشاء بروميس
في معظم الحالات ، ستستخدم ببساطة الوعود ، وليس إنشاءها ، ولكن لا يزال من المهم معرفة كيفية إنشائها.
بناء الجملة:
const promise = new Promise((resolve, reject) => { ... });
لقد أنشأنا وعدًا جديدًا باستخدام مُنشئ Promises ، وهو يأخذ حجة واحدة ، وهي رد اتصال ، يُعرف أيضًا باسم الوظيفة التنفيذية ، والتي تتطلب رد اتصالين ،
وتقرر وترفض .
يتم تنفيذ الوظيفة التنفيذية مباشرة بعد إنشاء الوعد. يتم إجراء وعد عن طريق استدعاء
العزم () ورفضه بالرفض
() . على سبيل المثال:
const promise = new Promise((resolve, reject) => { if(allWentWell) { resolve(' !'); } else { reject('- '); } });
الحل () ورفض () يأخذ وسيطة واحدة ، والتي يمكن أن تكون سلسلة أو رقم أو تعبير منطقي أو صفيف أو كائن.
دعونا نلقي نظرة على مثال آخر لنفهم تمامًا كيف يتم إنشاء الوعود.
const promise = new Promise((resolve, reject) => { const randomNumber = Math.random(); setTimeout(() => { if(randomNumber < .6) { resolve(' !'); } else { reject('- '); } }, 2000); });
أنا هنا أنشأت وعدًا جديدًا باستخدام مُنشئ Promis. يتم تنفيذ الوعد أو رفضه بعد ثانيتين من إنشائه. يتم تنفيذ الوعد إذا كان
العدد العشوائي أقل من 0.6 ورفض في حالات أخرى.
عندما يتم إنشاء وعد ، فسيكون معلقًا وسيتم تحديد قيمته.
بعد ثانيتين ، ينتهي المؤقت ، ويتم تنفيذ الوعد أو رفضه عشوائيًا ، وستكون قيمته هي القيمة التي تم تمريرها إلى وظيفة
العزم أو
الرفض . فيما يلي مثال لحالتين:
الانتهاء بنجاح:

رفض الوعد:
ملاحظة: يمكن تنفيذ الوعد أو رفضه مرة واحدة فقط. لن تؤثر الدعوات الإضافية
لحل () أو
الرفض () على حالة الوعد بأي شكل من الأشكال. مثال:
const promise = new Promise((resolve, reject) => { resolve('Promise resolved');
منذ أن تم استدعاء
العزم () أولاً ، أصبح الوعد الآن "مكتمل". الدعوة اللاحقة
بالرفض () لن تؤثر على حالة الوعد بأي شكل من الأشكال.
باستخدام Promis
الآن نحن نعرف كيفية إنشاء الوعود ، والآن دعونا نتعرف على كيفية تطبيق الوعد الذي تم إنشاؤه بالفعل. نستخدم الوعود باستخدام أساليب
then () و
catch () .
على سبيل المثال ، الاستعلام عن البيانات من واجهة برمجة التطبيقات باستخدام
الجلب ، والتي تؤدي إلى الوعد
بناء الجملة . (ثم) : الوعد. ثم (successCallback ، failureCallback)يتم استدعاء
successCallback إذا تم تنفيذ الوعد بنجاح. يستغرق وسيطة واحدة ، وهي القيمة التي تم تمريرها
لحل () .
يتم استدعاء
failCallback إذا تم رفض الوعد. يستغرق وسيطة واحدة ، وهي القيمة المعطاة
للرفض () .
مثال:
const promise = new Promise((resolve, reject) => { const randomNumber = Math.random(); if(randomNumber < .7) { resolve(' !'); } else { reject(new Error('- ')); } }); promise.then((data) => { console.log(data);
إذا تم تنفيذ الوعد ، يتم
استدعاء successCallback بالقيمة التي تم تمريرها
لحل () . وإذا تم رفض الوعد ،
فسيتم استدعاء failCallback بالقيمة التي تم تمريرها
للرفض ().
بناء جملة .catch () : Promise.catch (failureCallback)نحن نستخدم
catch () للتعامل مع الأخطاء. هذا أكثر قابلية للقراءة من خطأ معالجة داخل
failCallback داخل رد الاتصال الأسلوب
then () .
const promise = new Promise((resolve, reject) => { reject(new Error('- ')); }); promise .then((data) => { console.log(data); }) .catch((error) => { console.log(error);
سلسلة الوعد
يمكن أن تعيد أساليب
then () و
catch () أيضًا وعدًا جديدًا ، والذي يمكن معالجته بواسطة سلسلة من الآخر ثم () في نهاية الأسلوب السابق ().
نستخدم سلسلة من الوعود عندما نريد استكمال سلسلة من الوعود.
على سبيل المثال:
const promise1 = new Promise((resolve, reject) => { resolve('Promise1 '); }); const promise2 = new Promise((resolve, reject) => { resolve('Promise2 '); }); const promise3 = new Promise((resolve, reject) => { reject('Promise3 '); }); promise1 .then((data) => { console.log(data);
إذن ما الذي يحدث هنا؟
عندما
يتم الوفاء بوعد 1
، يتم استدعاء طريقة
then () ، والتي تقوم بإرجاع الوعد 2.
بعد ذلك ، عندما يتم
الوفاء بالوعد 2 ، يتم استدعاء
() مرة أخرى وإرجاع
الوعد 3 .
ونظرًا لأن الوعد 3 مرفوض ، فبدلاً من التالي
() ، يتم استدعاء
catch () ، والذي يعالج رفض
الوعد 3 .
ملاحظة: كقاعدة عامة ، تعد طريقة
catch () واحدة كافية لمعالجة رفض أي من الوعود في السلسلة ، إذا كانت هذه الطريقة في نهايتها.
خطأ شائع
الكثير من القادمين الجدد يرتكبون خطأ من خلال استثمار بعض الوعود داخل الآخرين. على سبيل المثال:
const promise1 = new Promise((resolve, reject) => { resolve('Promise1 '); }); const promise2 = new Promise((resolve, reject) => { resolve('Promise2 '); }); const promise3 = new Promise((resolve, reject) => { reject('Promise3 '); }); promise1.then((data) => { console.log(data);
على الرغم من أن هذا سيعمل بشكل جيد ، إلا أنه يعتبر نمطًا سيئًا ويجعل الكود أقل قابلية للقراءة. إذا كان لديك سلسلة من الوعود للتنفيذ ، فسيكون من الأفضل وضعها واحدة تلو الأخرى بدلاً من وضع واحدة داخل الأخرى.
Promise.all ()
تأخذ هذه الطريقة مجموعة من الوعود وتعيد وعدًا جديدًا سيتم تنفيذه عند تنفيذ أو رفض جميع الوعود داخل الصفيف بمجرد العثور على الوعد الذي تم رفضه. على سبيل المثال:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 2000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise2 '); }, 1500); }); Promise.all([promise1, promise2]) .then((data) => console.log(data[0], data[1])) .catch((error) => console.log(error));
هنا ، تكون الوسيطة الموجودة في الداخل
() عبارة عن صفيف يحتوي على قيم الوعود بنفس الترتيب الذي تم تمريرها به إلى
Promise.all () . (فقط في حالة تنفيذ جميع الوعود)
تم رفض الوعد لسبب رفض الوعد الأول في الصفيف المنقول. على سبيل المثال:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 2000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise2 '); }, 1500); }); Promise.all([promise1, promise2]) .then((data) => console.log(data[0], data[1])) .catch((error) => console.log(error));
لدينا هنا وعدان ، حيث يتم تنفيذ أحدهما بعد ثانيتين وينحرف الآخر بعد 1.5 ثانية. بمجرد رفض الوعد الثاني ، يتم رفض
الوعد الذي تم إرجاعه من
Promise.all () دون انتظار الأول.
قد تكون هذه الطريقة مفيدة عندما يكون لديك أكثر من وعد وتريد أن تعرف متى يتم الانتهاء من جميع الوعود. على سبيل المثال ، إذا طلبت بيانات من واجهة برمجة تطبيقات لجهة خارجية وتريد القيام بشيء مع هذه البيانات فقط عندما تنجح جميع الطلبات.
نتيجة لذلك ، لدينا
Promise.all () ، الذي ينتظر التنفيذ الناجح لجميع الوعود ، أو يكمل تنفيذه عندما يكتشف الفشل الأول في مجموعة الوعود.
Promise.race ()
تقبل هذه الطريقة مجموعة من الوعود وتُرجع وعدًا جديدًا واحدًا سيتم تنفيذه بمجرد الوفاء بالوعد الذي تم الوفاء به في الصفيف أو رفضه في حالة حدوث الوعد المرفوض مسبقًا. على سبيل المثال:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 1000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise2 '); }, 1500); }); Promise.race([promise1, promise2]) .then((data) => console.log(data))
لدينا هنا وعدان ، حيث يتم تنفيذ أحدهما بعد ثانية واحدة ، والآخر ينحرف بعد 1.5 ثانية. بمجرد الوفاء بالوعد الأول ، سيكون للوعد الذي يتم إرجاعه من Promise.race () الحالة التي تم الوفاء بها دون انتظار حالة الوعد الثاني.
هنا ،
البيانات التي يتم تمريرها إلى
then () هي قيمة الوعد المنفذ الأول.
نتيجة لذلك ، ينتظر
Promise.race () الوعد الأول ويأخذ مكانته كحالة الوعد المرتجع.
تعليق مؤلف الترجمة: ومن هنا جاء الاسم نفسه. سباق - سباقالخاتمة
لقد تعلمنا ما هي الوعود وماذا يأكلون في جافا سكريبت. تتكون الوعود من جزأين 1) إنشاء وعد و 2) استخدام الوعد. في معظم الأحيان سوف تستخدم الوعود بدلاً من إنشاءها ، ولكن من المهم معرفة كيفية إنشائها.
هذا كل شيء ، آمل أن يكون هذا المقال مفيدًا لك!