تعج هذه المقالة بشكل رئيسي استخدام الوعود.
لفترة طويلة ، كانت JavaScript تعامل دائمًا بشكل غير متزامن في شكل رد اتصال ، وآلية رد الاتصال في مجال التنمية الأمامية تتأرجح بعمق في قلوب الناس. عند تصميم واجهات برمجة التطبيقات ، سواء كانت الشركة المصنعة للمتصفح أو مطور SDK أو مؤلف مكتبة مختلفة ، فإنها تتبع روتين رد الاتصال بشكل أساسي.
في السنوات الأخيرة ، مع النضج التدريجي لنموذج تطوير JavaScript ، ولدت مواصفات CommonJS ، بما في ذلك اقتراح مواصفات الوعد. لقد غيرت Promise كتابة البرمجة JS غير المتزامنة تمامًا ، مما يجعل البرمجة غير المتزامنة سهلة الفهم.
في نموذج رد الاتصال ، نفترض أنه يجب تنفيذ قائمة انتظار غير متزامنة ، وقد يبدو الرمز هكذا:
loadimg ('A.JPG' ، function () {loadimg ('B.JPG' ، function () {loadimg ('c.jpg' ، function () {console.log ('all done!') ؛}) ؛}) ؛}) ؛هذا هو ما نحن في كثير من الأحيان هرم رد الاتصال. عندما يكون هناك العديد من المهام غير المتزامنة ، فإن الحفاظ على عدد كبير من عمليات الاسترجاعات سيكون كارثة. في الوقت الحاضر ، node.js تحظى بشعبية كبيرة. يبدو أن العديد من الفرق ترغب في استخدامها لعمل شيء ما للتعامل مع "الموضة". بمجرد الدردشة مع زميل في التشغيل والصيانة ، خططوا أيضًا لاستخدام Node.js للقيام بشيء ما ، ولكن عندما يفكرون في طبقات عمليات استدعاءات JS ، يتم تثبيتها.
حسنًا ، انتهى الهراء ، دعنا نصل إلى الموضوع.
قد يكون الوعد على دراية بالجميع ، لأن مواصفات الوعد قد خرجت لفترة طويلة ، وقد تم إدراج الوعد في ES6 ، وقد نفذت الإصدارات العليا من متصفحات Chrome و Firefox وعدًا ، ولكن هناك أقل من واجهات برمجة التطبيقات الشهيرة من مكتبة فئة الوعد الشهيرة.
يمكن فهم ما يسمى الوعد حرفيًا على أنه "وعد" ، مما يعني أن A B ، B يعيد "وعدًا" إلى A ، ثم يمكن أن يكتب هذا عند كتابة الخطة: عندما يعيد B النتيجة ، A تنفيذ الخطة S1. على العكس من ذلك ، إذا لم يعط B النتيجة المطلوبة لسبب ما ، فإن A تنفذ خطة الطوارئ S2 ، بحيث تكون جميع المخاطر المحتملة ضمن نطاق A يمكن التحكم فيها.
تتم ترجمة الجملة أعلاه إلى رمز مشابه لـ:
var resb = b () ؛ var runa = function () {resb.then (execs1 ، execs2) ؛} ؛ runa () ؛مجرد النظر إلى السطر أعلاه من التعليمات البرمجية ، يبدو أنه لا يوجد شيء خاص. لكن الواقع قد يكون أكثر تعقيدًا من هذا. لإنجاز شيء واحد ، يعتمد A May على استجابة أكثر من شخص واحد B. قد يتطلب الأمر سؤال العديد من الأشخاص في نفس الوقت ثم تنفيذ الخطة التالية بعد تلقي جميع الإجابات. قد تبدو الترجمة النهائية إلى الكود هكذا:
var resb = b () ؛ var resc = c () ؛ ... var runa = function () {reqb .Then (resc ، execs2) .Then (resd ، execs3).هنا ، يتم استخدام آليات المعالجة المختلفة عندما يستجيب كل مستجيب لا يتماشى مع التوقعات. في الواقع ، لا تتطلب مواصفات الوعد ذلك ، ولا يمكنك القيام بأي شيء (أي ، لا تمر في المعلمة الثانية في ذلك الوقت) أو التعامل معها بشكل موحد.
حسنًا ، دعنا نتعرف على الوعد/مواصفات A+:
then (يمكن القول أن هو جوهر الوعد) ، ومن ثم يجب أن تعيد الوعد. ثم يمكن استدعاء نفس الوعد عدة مرات ، وترتيب تنفيذ عمليات الاسترجاعات يتوافق مع الطلب عند تعريفهاكما ترون ، لا يوجد الكثير من المحتوى في مواصفات الوعد ، حتى تتمكن من محاولة تنفيذ الوعد التالي بنفسك.
فيما يلي تنفيذ بسيط لوعد بأنني أشرت إلى العديد من مكتبات الوعد. يرجى الانتقال إلى Promisea في الكود.
تحليل موجز للأفكار:
يقبل وعد المنشئ resolver دالة ، والذي يمكن فهمه على أنه تمرير مهمة غير متزامنة. يقبل Resolver معلمتين ، أحدهما عبارة عن رد اتصال عند النجاح والآخر هو رد اتصال عند الفشل. هاتان المعلمتان تساوي المعلمات التي تم تمريرها خلال ذلك الوقت.
والثاني هو تنفيذ آنذاك. نظرًا لأن الوعد يتطلب بعد ذلك أن يعيد الوعد ، سيتم إنشاء وعد جديد عند استدعاء ذلك ، والذي سيتم _next على الوعد الحالي. لا ستُرجع مكالمات متعددة لنفس الوعد فقط إلى _next تم إنشاؤها مسبقًا.
نظرًا لأن المعلمتين المقبولتين من خلال الطريقة التين تكون اختيارية ولا يوجد أي قيود على النوع ، يمكن أن تكون وظيفة أو قيمة محددة أو وعد آخر. فيما يلي التنفيذ المحدد لـ:
promise.prototype.then = function (حل ، رفض) {var next = this._next || (this._next = promise ()) ؛ var status = this.status ؛ var x ؛ if ('pending' === status) {iSfn (حل) && this._resolves.push (حل) ؛ ISFN (رفض) && this._rejects.push (رفض) ؛ العودة بعد ذلك ؛ } if ('حل' === الحالة) {if (! isfn (حل)) {next.Resolve (حل) ؛ } آخر {try {x = desolve (this.value) ؛ solvex (التالي ، x) ؛ } catch (e) {this.reject (e) ؛ }} العودة التالية ؛ } if ('rejected' === status) {if (! isfn (refect)) {next.reject (refect) ؛ } آخر {try {x = refect (this.reason) ؛ solvex (التالي ، x) ؛ } catch (e) {this.reject (e) ؛ }} العودة التالية ؛ }} ؛هنا ، ثم قام بتبسيط تنفيذ مكتبات فئة الوعد الأخرى ، والتنفيذ أكثر تعقيدًا من هذا ، ولديه أيضًا وظائف أكثر. على سبيل المثال ، هناك معلمة ثالثة - الإخطار ، والتي تشير إلى التقدم الحالي للوعد ، وهو مفيد للغاية عند تحميل ملفات التصميم ، وما إلى ذلك. يمكن للطلاب المهتمين الرجوع إلى تنفيذ أنواع أخرى من مكتبات الوعد.
على أساس ذلك الوقت ، يجب أن تكون هناك حاجة إلى طريقتين على الأقل ، وهما ، لإكمال تحويل حالة الوعد من المعلق إلى حل أو رفض ، وتنفيذ قائمة انتظار رد الاتصال المقابلة ، وهي resolve() reject() الأساليب.
في هذه المرحلة ، تم تصميم وعد بسيط. فيما يلي تطبيقات بسيطة للوظيفة الموعودة التالية:
وظيفة Sleep (ms) {return function (v) {var p = promise () ؛ setTimeOut (function () {p.resolve (v) ؛} ، ms) ؛ العودة P ؛ } ؛} ؛ وظيفة getImg (url) {var p = promise () ؛ var img = new image () ؛ img.onload = function () {p.resolve (this) ؛ } ؛ img.onerror = function (err) {p.Reject (err) ؛ } ؛ img.url = url ؛ العودة p ؛} ؛ نظرًا لأن مُنشئ الوعد يقبل مهمة غير متزامنة كمعلمة ، يمكن أيضًا تسمية getImg على هذا النحو:
وظيفة getImg (url) {return promise (function (حل ، رفض) {var img = new image () ؛ img.onload = function () {desolve (this) ؛} ؛ img.onerror = function (err) {reject (err) ؛} ؛ img.url = url ؛}) ؛} ؛بعد ذلك (لحظة مشاهدة المعجزة) ، لنفترض أن هناك شرطًا من BT لتنفيذ هذا: الحصول على تكوين JSON بشكل غير متزامن ، وحوض بيانات JSON والحصول على الصور في الداخل ، ثم قم بتحميل الصور بالتسلسل ، وإعطاء تأثير تحميل عند عدم تحميل صورة.
وظيفة addimg (img) {$ ('#list'). find ('> li: last-child'). html (''). إلحاق (img) ؛} ؛ وظيفة prepend () {$ ('<li>') .html ('loading ...') .appendto ($ ('list') ؛} ؛ getData ('map.json') .Then (الوظيفة (البيانات) {$ ('h4'). html (data.name) ؛ return data.list.reduce (function (promise ، item) {return promise .then (prepend) .then (1000) .then (function () {return getimg (item.url) ؛ Promise.Resolve ()) ؛تمت إضافة النوم هنا فقط لرؤية التأثير ، يمكنك النقر لعرض العرض التوضيحي! بالطبع ، يمكن الاطلاع على مثال Node.js هنا.
هنا ، الطريقة الثابتة Promise.resolve(v) ببساطة إرجاع وعد مع V كنتيجة إيجابية. لا يمكن تمرير V في ، أو يمكن أن يكون دالة أو كائن أو وظيفة تحتوي على then (على سبيل المثال ، يمكن ذلك ذلك).
تشمل الأساليب الثابتة المماثلة Promise.cast(promise) ، الذي يولد وعدًا بوعد كنتيجة إيجابية ؛
Promise.reject(reason)
قد تكون سيناريوهات الاستخدام الفعلية لدينا معقدة للغاية ، وغالبًا ما تتطلب تنفيذ مهام غير متزامنة متعددة بشكل غير متزامن أو متوازي أو متسلسل. في هذا الوقت ، يمكنك عمل امتدادات مختلفة لوعدها ، مثل تنفيذ Promise.all() ، وقبول قائمة انتظار الوعود وانتظار إكمالها قبل المتابعة ، وعلى سبيل المثال ، Promise.any() ، عندما تكون أي من قوائم الوعود في حالة الانتهاء ، سيتم تشغيل العملية التالية.
يمكنك الرجوع إلى هذه المقالة في وعود HTML5Rocks JavaScript. في الوقت الحالي ، تحتوي المتصفحات المتقدمة مثل Chrome و Firefox على كائنات وعد مدمجة ، حيث توفر المزيد من واجهات التشغيل ، مثل Promise.all() ، والتي تدعم تمرير مجموعة الوعد ، ثم يتم تنفيذها عند اكتمال جميع الوعود. هناك أيضًا استثناء أكثر ودية وقوية ، والذي يجب أن يكون كافياً للتعامل مع البرمجة اليومية غير المتزامنة.
نفذت مكتبات JS الأكثر شعبية اليوم وعدًا بدرجات متفاوتة ، مثل Dojo و jQuery و Zepto و when.js و q ، وما إلى ذلك ، ولكن Deferred معظم الأشياء المكشوفة. أخذ jQuery (Zepto مماثل) كمثال ، قم بتنفيذ getImg() أعلاه:
وظيفة getImg (url) {var def = $ .deferred () ؛ var img = new image () ؛ img.onload = function () {def.Resolve (this) ؛ } ؛ img.onerror = function (err) {def.Reject (err) ؛ } ؛ img.src = url ؛ إرجاع def.promise () ؛} ؛ بالطبع ، في jQuery ، تعود العديد من العمليات المؤجلة أو الوعد ، مثل animate ajax :
. $ .ajax (Options2)) .Then (function () {console.log ('all done.') ؛} ، function () {console.error ('هناك شيء خاطئ.') ؛}) ؛ يقوم jQuery أيضًا بتنفيذ أساليب done() و fail() ، والتي هي في الواقع اختصارات للطريقة آنذاك.
للتعامل Promise.all() قوائم الوعود ، يقوم jQuery بتنفيذ طريقة $.when()
بالنسبة للمكتبات الفصول الدراسية الأخرى ، تجدر الإشارة هنا إلى أنه عندما يكون لدى js رمز صغير ، فإنه ينفذ تمامًا الوعد ، ويدعم المتصفح و node.js ، ويوفر واجهات برمجة التطبيقات الأكثر ثراءً ، وهو خيار جيد. بسبب قيود المساحة ، لن نوسعها بعد الآن.
نرى أنه بغض النظر عن مدى تعقيد تنفيذ الوعد ، فإن استخدامه بسيط للغاية والرمز التنظيمي واضح للغاية. من الآن فصاعدًا ، ليست هناك حاجة للتعذيب عن طريق رد الاتصال.
وأخيرا ، الوعد أنيق جدا! لكن الوعد فقط يحل مشكلة التعشيش العميق لعمليات الاسترجاعات. إنه المولد الذي يبسط حقًا برمجة JavaScript غير المتزامنة. على جانب Node.js ، يوصى بالنظر في المولد.
المقالة التالية ، مولد الدراسة.
نص GitHub الأصلي: https://github.com/chemdemo/chemdemo.github.io/issues/6