حاليًا ، يشارك عدد كبير من العمليات غير المتزامنة في الطلب ، وتميل الصفحات الفعلية بشكل متزايد إلى تطبيقات صفحة واحدة. في المستقبل ، يمكنك استخدام العمود الفقري والزاوي والضربة القاضية والأطر الأخرى ، ولكن مشكلة البرمجة غير المتزامنة هي أول مشكلة تواجهها. مع ظهور العقد ، أصبحت البرمجة غير المتزامنة موضوعًا ساخنًا للغاية. بعد فترة من التعلم والممارسة ، يتم تلخيص بعض تفاصيل البرمجة غير المتزامنة.
1. تصنيف البرمجة غير المتزامنة
تتضمن طرق حل المشكلة غير المتزامنة بشكل عام: رد الاتصال المباشر ، وضع Pub/Sub (وضع الحدث) ، مكتبة التحكم في المكتبة غير المتزامنة (مثل Async ، متى) ، الوعد ، المولد ، إلخ.
1.1 وظيفة رد الاتصال
تُستخدم وظائف رد الاتصال بشكل شائع لحل الحلول غير المتزامنة ، وغالبًا ما يتم تعريضها واستخدامها ، وسهلة الفهم وسهلة التنفيذ في المكتبات أو الوظائف. هذه أيضًا طريقة يستخدمها الأشخاص غالبًا عند استخدام البرمجة غير المتزامنة.
ومع ذلك ، فإن طريقة وظيفة رد الاتصال لديها المشكلات التالية:
1. قد يتشكل هرم متداخل من الشر ، وليس من السهل قراءته المدونة ؛
2. يمكن أن تكون وظيفة رد اتصال واحد فقط مقابلة ، والتي تصبح حدًا في العديد من السيناريوهات.
1.2 الحانة/الوضع الفرعي (الحدث)
يسمى هذا النمط أيضًا وضع الحدث ، وهو تنقيح وظائف رد الاتصال وهو شائع جدًا في مكتبات الفصل مثل jQuery.
لا يعاني وضع المشترك في الحدث من مشكلة المكالمات المتزامنة وغير المتزامنة ، ولكن في العقدة ، يتم تشغيل المكالمات في الغالب بشكل غير متزامن مع حلقة الحدث. غالبًا ما يستخدم هذا الوضع لفصل منطق العمل. لا يحتاج ناشرو الأحداث إلى الانتباه إلى وظيفة رد الاتصال المسجلة ، ولا يحتاجون إلى الانتباه إلى عدد وظائف رد الاتصال. يمكن نقل البيانات بمرونة من خلال الرسائل.
فوائد هذا النمط هي: 1. من السهل الفهم ؛ 2. لم يعد يقتصر على وظيفة رد الاتصال.
عندما يتعلق الأمر بالأشياء السيئة: 1. تحتاج إلى استخدام مكتبة الفصل ؛ 2. ترتيب الأحداث ووظائف رد الاتصال مهم للغاية
نسخة الكود كما يلي:
var img = document.queryselect (#ID) ؛
img.addeventListener ('load' ، function () {
// تم تحميل الصورة
......
}) ؛
img.addeventListener ('error' ، function () {
// حدث خطأ ما
......
}) ؛
هناك مشكلتان في الكود أعلاه:
أ. تم بالفعل تحميل IMG ، وترتبط وظيفة رد الاتصال في هذا الوقت. نتيجة لذلك ، لن يتم تنفيذ رد الاتصال ، ولكن لا يزال يأمل في تنفيذ وظيفة رد الاتصال المقابلة.
نسخة الكود كما يلي:
var img = document.queryselect (#ID) ؛
وظيفة تحميل () {
...
}
if (img.complete) {
حمولة()؛
} آخر {
img.addeventListener ('load' ، load) ؛
}
img.addeventListener ('error' ، function () {
// حدث خطأ ما
......
}) ؛
ب. غير قادر على التعامل مع الاستثناءات بشكل جيد
الخلاصة: إن آلية الحدث هي الأنسب للتعامل مع الأحداث المتكررة على نفس الكائن ، وليس هناك حاجة للنظر في الحدث قبل ربط وظيفة رد الاتصال.
1.3 مكتبة التحكم غير المتزامنة
تتضمن المكتبات الحالية غير المتزامنة بشكل أساسي Q ، when.js ، win.js ، rsvp.js ، إلخ.
سمة هذه المكتبات هي أن الكود خطي ويمكن كتابته من أعلى إلى أسفل ، تمشيا مع العادات الطبيعية.
تختلف الأشياء السيئة أيضًا في الأساليب ، والتي لا تفسد من قراءة وزيادة تكاليف التعلم.
1.4 وعد
يتم ترجمة الوعد إلى الصينية كوعد. شخصيا ، بعد الانتهاء من عدم التزامن ، سوف يعطي نتيجة خارجية (النجاح أو الفشل) ووعد بأن النتيجة لن تتغير بعد الآن. بمعنى آخر ، يعكس الوعد قيمة نتيجة الإرجاع النهائية للعملية (يمثل الوعد القيمة النهائية التي تم إرجاعها من الانتهاء من عملية ما). في الوقت الحاضر ، تم إدخال الوعد في مواصفات ES6 ، وقام المتصفحات المتقدمة مثل Chrome و Firefox بتنفيذ هذه الطريقة الأصلية داخليًا ، والتي تعد مريحة للغاية للاستخدام.
فيما يلي خصائص الوعد من الجوانب التالية:
1.4.1 الحالة
أنه يحتوي على ثلاث حالات: معلق ، الوفاء ، ورفض. لا يمكن للولايات الثلاث أن تخضع فقط لانتقاليتين (من المعلق ---> تم الوفاء به ، معلق-> مرفوض) ، ويمكن أن يحدث انتقال الدولة مرة واحدة فقط.
1.4.2 ثم الطريقة
يتم استخدام الطريقة ثم لتحديد وظيفة رد الاتصال بعد اكتمال الحدث غير المتزامن.
يمكن القول أن هذه الطريقة هي طريقة الروح للوعد ، والتي تجعل الوعد مليئًا بالسحر. هناك العديد من المظاهر المحددة على النحو التالي:
أ) ثم تعيد الطريقة الوعد. وهذا يتيح العمليات التسلسلية لعمليات غير متزامنة متعددة.
فيما يتعلق بالدائرة الصفراء 1 في الشكل أعلاه ، فإن معالجة القيمة هي جزء أكثر تعقيدًا من الوعد. يتم تقسيم معالجة القيمة إلى حالتين: كائن الوعد والكائن غير العمومي.
عندما لا تكون القيمة نوع الوعد ، ما عليك سوى استخدام القيمة كقيمة المعلمة لحل الوعد الثاني ؛ عندما يكون نوع الوعد ، يتم تحديد حالة ومعلمات PROMENT2 بالكامل من خلال القيمة. يمكن اعتبار أن PROMSIE2 هو دمية ذات قيمة ، و Promise2 هو مجرد جسر يربط مختلف غير متزامن.
نسخة الكود كما يلي:
promise.prototype.Then = وظيفة (onfulfilled ، onRejected) {
إرجاع وعد جديد (الوظيفة (حل ، رفض) {// الوعد هنا تم وضع علامة على Promise2
مقبض({
onfulfilled: onfulfilled ،
onrejected: onrejected ،
حل: حل ،
رفض: رفض
})
}) ؛
}
مقبض الوظيفة (مؤجل) {
var handlefn ؛
إذا (الحالة === '
handlefn = deferred.onfulfilled ؛
} آخر إذا (state === 'rejected') {
handlefn = مؤلف.
}
var ret = handlefn (value) ؛
deferred.Resolve (ret) ؛ // لاحظ أن العزم في هذا الوقت هو عزم الوعد 2
}
وظيفة حل (VAL) {
if (val && typeof val.then === 'function') {
Val.Then (حل) ؛ // إذا كان VAL كائن الوعد أو كائن الوعد الطبقي ، فإن حالة الوعد 2 تحددها Val بالكامل
يعود؛
}
إذا كانت (رد الاتصال) {// رد الاتصال هي وظيفة رد الاتصال المحددة
رد الاتصال (VAL) ؛
}
}
ب) يتم تنفيذ التحويل بين المكتبات المتعددة غير المتزامنة.
هناك كائن يسمى Thenable في غير متزامن ، والذي يشير إلى كائن مع الطريقة آنذاك. طالما أن كائن كائن يحتوي على طريقة آنذاك ، يمكن تحويله ، على سبيل المثال:
نسخة الكود كما يلي:
var مؤلف = $ ('aa.ajax') ؛ // !! deferred.Then === true
var p = promise.Resolve (مؤجل) ؛
P.Then (......)
1.4.3 الوعد المشترك/المواصفات
حاليًا ، هناك مواصفات وعد/A و Promise/A+ للمواصفات المتعلقة بالوعد ، مما يدل على أن تنفيذ الوعد معقد للغاية.
نسخة الكود كما يلي:
ثم (الوفاء ، الرفض ، ProgressHandler)
1.4.4 ملاحظات
وظيفة رد الاتصال في الوعد تشارك القيمة. في معالجة النتائج ، يتم تمرير القيمة كمعلمة إلى وظيفة رد الاتصال المقابلة. إذا كانت القيمة كائنًا ، فاحرص على عدم تعديل القيمة بسهولة.
نسخة الكود كما يلي:
var p = promise.Resolve ({x: 1}) ؛
p.then (وظيفة (val) {
console.log ('رد الاتصال الأول:'+val.x ++) ؛
}) ؛
p.then (وظيفة (val) {
console.log ('رد الاتصال الثاني:' + val.x)
})
// رد الاتصال الأول: 1
// رد الاتصال الثاني: 2
1.5 مولد
تعتمد جميع الطرق المذكورة أعلاه على وظيفة رد الاتصال لإكمال العمليات غير المتزامنة ، وهي ليست أكثر من مجرد تغطية وظيفة رد الاتصال. يقترح ES6 المولد ، الذي يضيف طرقًا لحل العمليات غير المتزامنة ولم يعد مكتملًا بناءً على وظائف رد الاتصال.
أكبر ميزة للمولد هي أنه يمكن أن تتوقف وإعادة تشغيل وظائف ، والتي تفضي إلى حل العمليات غير المتزامنة. يمكن أن يؤدي الجمع بين توقف المولد مع معالجة استثناءات Promise إلى حل مشكلة البرمجة غير المتزامنة بشكل أكثر أناقة. مرجع تنفيذ محدد: كايل سيمبسون
2. مشاكل في البرمجة غير المتزامنة
2.1 معالجة الاستثناء
أ) تشمل الأحداث غير المتزامنة رابطين: إصدار طلبات غير متزامنة ونتائج المعالجة. يتم توصيل هذين الرابطين من خلال حلقات الأحداث. ثم عند محاولة التقاط الاستثناء ، تحتاج إلى التقاطه.
نسخة الكود كما يلي:
يحاول {
ASINCEVENT (رد الاتصال) ؛
} catch (err) {
......
}
لا يمكن للرمز المذكور أعلاه الالتحاق بالاستثناء في رد الاتصال ، ويمكنه فقط الحصول على الاستثناء في عملية الطلب. هذا له مشاكل: إذا تم الانتهاء من إصدار الطلب ومعالجة الطلب من قبل شخصين ، فهناك مشاكل عند التعامل مع الاستثناءات؟
ب) يمنح الوعد تسليم الاستثناء ، والذي يجلب بعض الفوائد لضمان عدم حظر الكود في المشاريع الفعلية. ومع ذلك ، إذا كان هناك العديد من الأحداث غير المتزامنة ، فليس من السهل معرفة الحدث غير المتزامن الذي ينتج استثناء.
نسخة الكود كما يلي:
// وصف المشهد: معلومات إنذار سعر العرض في CRM ، بما في ذلك المعلومات التنافسية. ومع ذلك ، فإن الأمر يستغرق وقتًا طويلاً للحصول على المعلومات التنافسية. من أجل تجنب الاستعلام البطيء ، تقسم الواجهة الخلفية سجلًا إلى قطعتين للحصول عليه بشكل منفصل.
// الخطوة 1: الحصول على معلومات إنذار السعر ، بالإضافة إلى معلومات المنافسة
وظيفة getPriceAlarmData () {
إرجاع وعد جديد (وظيفة (حل) {
y.io (url ، {
الطريقة: "الحصول على" ،
البيانات: params ،
On: Function () {
النجاح: الوظيفة (المعرف ، البيانات) {
حل (المنبه) ؛
}
}
}) ؛
}) ؛
}
// بعد الحصول على معلومات الإنذار ، انتقل للحصول على معلومات المنافسة
getPriceAlarmData (). ثم (وظيفة (البيانات) {
// عرض البيانات ، بالإضافة إلى المعلومات التنافسية
عرض (بيانات) ؛
إرجاع وعد جديد (وظيفة (حل) {
y.io (url ، {
الطريقة: "الحصول على" ،
البيانات: {AlarmList: Data} ،
On: Function () {
النجاح: الوظيفة (المعرف ، compdata) {
حل (compdata) ؛
}
}
}) ؛
}) ؛
}) // بعد الحصول على جميع البيانات ، تقديم معلومات المنافسة
.Then (وظيفة (البيانات) {
// تقديم معلومات العطاءات
عرض (بيانات)
} ، وظيفة (خطأ) {
// استثناء التعامل
console.log (err) ؛
}) ؛
يمكن تحويل الرمز أعلاه إلى ما يلي:
نسخة الكود كما يلي:
يحاول{
// الحصول على معلومات الإنذار بخلاف المنافسة
var eravData = erastDataExceptCompare () ؛
عرض (eravData) ؛
// استفسار معلومات المنافسة بناءً على معلومات الإنذار
var aredata = getCompareInfo (eravData) ؛
عرض (مقارنة) ؛
} catch (err) {
console.log (err.message) ؛
}
في المثال أعلاه ، يتم التعامل مع الاستثناء في النهاية ، بحيث عندما يحدث استثناء في رابط معين ، لا يمكننا معرفة بالضبط الحدث الذي يتم إنشاؤه.
2.2 jQuery.deferred مشكلة
يتم تنفيذ العمليات غير المتزامنة أيضًا في jQuery ، لكنها لا تتوافق مع مواصفات Promise/A+ في التنفيذ ، وينعكس بشكل أساسي في الجوانب التالية:
أ. عدد المعلمات: يمكن أن يقبل الوعد القياسي معلمة واحدة فقط ، في حين أن jQuery يمكن أن تمرير معلمات متعددة
نسخة الكود كما يلي:
وظيفة asyncinjquery () {
var d = new $ .deferred () ؛
setTimeout (function () {
D.Resolve (1 ، 2) ؛
} ، 100) ؛
العودة D.Promise ()
}
asyncinjquery (). ثم (الدالة (val1 ، val2) {
console.log ('الإخراج:' ، val1 ، val2) ؛
}) ؛
// الإخراج: 1 2
ب. التعامل مع الاستثناءات في معالجة النتائج
نسخة الكود كما يلي:
وظيفة ASYNCINPROMISE () {
إرجاع وعد جديد (وظيفة (حل) {
setTimeout (function () {
var jsonstr = '{"name": "mt}' ؛
حل (jsonstr) ؛
} ، 100) ؛
}) ؛
}
asyncinpromise (). ثم (وظيفة (val) {
var d = json.parse (val) ؛
console.log (D.Name) ؛
}). ثم (NULL ، الوظيفة (err) {
console.log ('show error:' + err.message) ؛
}) ؛
// إظهار الخطأ: نهاية غير متوقعة للإدخال
وظيفة asyncinjquery () {
var d = new $ .deferred () ؛
setTimeout (function () {
var jsonstr = '{"name": "mt}' ؛
D.Resolve (JSONST) ؛
} ، 100) ؛
العودة D.Promise ()
}
asyncinjquery (). ثم (وظيفة (val) {
var d = json.parse (val) ؛
console.log (D.Name) ؛
}). ثم (الدالة (v) {
console.log ("النجاح:" ، v.name) ؛
} ، وظيفة (خطأ) {
console.log ('show error:' + err.message) ؛
}) ؛
// Syntaxerror غير الموقوف: نهاية غير متوقعة من الإدخال
يمكن أن نرى من هذا أن الوعد يعالج نتيجة وظيفة رد الاتصال ، والتي يمكن أن تلتقط استثناءات أثناء تنفيذ وظيفة رد الاتصال ، ولكن jquery.deferred لا يمكن.