أولاً ، دعونا نفهم ماهية الخانق
1. التعريف
إذا قمت بتشديد الحنفية حتى يتدفق الماء في شكل قطرات مائية ، فستجد أنه من حين لآخر ، سوف يتدفق قطرة من الماء.
بمعنى أنه يتم تعيين دورة التنفيذ مسبقًا ، وعندما يكون الوقت الذي يتم فيه استدعاء الإجراء أكبر من أو يساوي دورة التنفيذ ، يتم تنفيذ الإجراء ، ثم يتم إدخال الدورة الجديدة التالية.
تعريف الواجهة:
* عند إرجاع عنصر التحكم في التردد ، تتم استدعاء الوظيفة بشكل مستمر ، يقتصر تردد تنفيذ الإجراء على الأوقات/ التأخير* Param Delay {number} وقت التأخير ، وحدة milliseconds* @param الإجراء {function} تطلب الوظيفة المرتبطة بها ، والوظيفة التي يجب استدعاؤها في التطبيق الفعلي* return2. التنفيذ البسيط
var throttle = function (تأخير ، الإجراء) {var last = 0return function () {var curr = +new date () if (curr - last> delay) {action.apply (this ، alctions) last = curr}}}اسمحوا لي أن أشرح هذه الوظيفة الخنق بعناية أدناه.
في حدث DOM للمتصفح ، سيتم تشغيل بعض الأحداث بشكل مستمر مع عمليات المستخدم. على سبيل المثال: تغيير حجم نافذة المتصفح ، وقم بتمرير صفحة المتصفح ، و Mousemove. وهذا يعني أنه عندما يقوم المستخدم بإعداد عمليات المتصفح هذه ، إذا كانت طريقة معالجة الأحداث المقابلة مرتبطة بالبرنامج النصي ، فسيتم تشغيل هذه الطريقة بشكل مستمر.
هذا ليس ما نريده ، لأنه في بعض الأحيان إذا كانت طريقة معالجة الأحداث كبيرة نسبيًا ، فإن عمليات DOM مثل المعقدة ، وتؤدي ذلك باستمرار إلى هذه الأحداث ، ستؤدي إلى خسائر في الأداء ، مما يؤدي إلى انخفاض في تجربة المستخدم (استجابة واجهة المستخدم البطيئة ، متصفح عالق ، إلخ). لذلك عادةً ما نضيف منطقًا إلى الحدث المقابل لتأخير التنفيذ.
بشكل عام ، نستخدم الكود التالي لتنفيذ هذه الوظيفة:
var count = 0 ؛ function testfn () {console.log (count ++) ؛ } // عندما يقوم المتصفح بتغيير حجم // 1. قم بمسح المؤقت السابق // 2. أضف مؤقتًا لتأخير الوظيفة الحقيقية testfn بمقدار 100 مللي ثانية لإعداد نافذة. ClearTimeout (مؤقت) ؛ timer = setTimeOut (function () {testfn () ؛} ، 100) ؛} ؛سيجد الطلاب الحذرون أن الكود أعلاه خاطئ بالفعل. هذه مشكلة ستجعلها المبتدئين: يجب حفظ قيمة الإرجاع لوظيفة SetTimeout في متغير عالمي نسبي ، وإلا سيتم إنشاء جهاز توقيت جديد في كل مرة يتم فيها تغيير حجم التغييرات ، والتي لن تحقق التأثير الذي نرسله.
لذلك قمنا بتعديل الكود:
var timer = null ؛ window.onresize = function () {clearTimeOut (timer) ؛ timer = setTimeOut (function () {testfn () ؛} ، 100) ؛} ؛في هذا الوقت ، يكون الرمز طبيعيًا ، ولكن هناك مشكلة جديدة أخرى - يتم إنشاء مؤقت متغير عالمي. هذا شيء لا نريد رؤيته. إذا كانت هذه الصفحة تحتوي على وظائف أخرى ، فإنها تسمى أيضًا Timer. الرموز المختلفة سوف تسبب تعارضات من قبل. لحل هذه المشكلة ، نحتاج إلى استخدام ميزة لغة JavaScript: إغلاق الإغلاق. يمكن للقراء التعرف على المعرفة ذات الصلة في MDN. الرمز المعدل كما يلي:
/*** طريقة اختناق الوظيفة* param وظيفة استدعاء تأخير الدالة* param تأخير المدة التي تستغرقها طريقة تأخير* return لتأخير التنفيذ*/var throttle = function (fn ، delay) {var timer = null ؛ Return Function () {cleartimeout (timer) ؛ timer = setTimeOut (function () {fn () ؛} ، delay) ؛ }} ؛ window.onresize = Throttle (testfn ، 200 ، 1000) ؛نستخدم وظيفة الإغلاق (خانق خانق) لوضع المؤقت داخليًا وإعادة وظيفة معالجة التأخير. وبهذه الطريقة ، يكون متغير المؤقت غير مرئي للخارج ، ولكن يمكن أيضًا الوصول إلى متغير المؤقت عند تشغيل وظيفة التأخير الداخلي.
بالطبع ، ليس من السهل على المبتدئين فهم المبتدئين. يمكننا تغيير طريقة الكتابة لفهم:
var throuttle = function (fn ، delay) {var timer = null ؛ Return Function () {cleartimeout (timer) ؛ timer = setTimeOut (function () {fn () ؛} ، delay) ؛ }} ؛ var f = throuttle (testfn ، 200) ؛ window.onresize = function () {f () ؛} ؛فيما يلي وجهة نظر: الوظيفة التي يتم إرجاعها بواسطة الخانق بعد استدعاءها هي الوظيفة الحقيقية التي يجب استدعاؤها عند تشغيل onResize
الآن يبدو أن هذه الطريقة قريبة من الكمال ، ولكن هذا ليس هو الحال في الاستخدام الفعلي. على سبيل المثال:
إذا قام المستخدم بتغيير حجم نافذة المتصفح باستمرار ، فلن يتم تنفيذ وظيفة معالجة التأخير مرة واحدة
لذلك نحتاج إلى إضافة وظيفة أخرى: عندما يقوم المستخدم بتغيير حجمه ، يجب تشغيله مرة واحدة على الأقل خلال فترة زمنية معينة. نظرًا لأنه في غضون فترة زمنية معينة ، يمكن أن تستغرق شرط الحكم هذا الوقت الحالي مللي ثانية ، وستقوم كل استدعاء دالة بطرح الوقت الحالي من وقت الاتصال الأخير ، ثم يحكم على أنه إذا كان الفرق أكبر من فترة زمنية معينة ، فسيتم إرسالها مباشرة ، وإلا فإنها ستتبع منطق تأخير المهلة.
ما يجب الإشارة إليه في الكود التالي هو:
تشبه وظيفة المتغير السابق وظيفة المؤقت. كلاهما هما المعرفات التي تسجل في المرة الأخيرة ويجب أن تكون متغيرات عالمية نسبية
إذا كانت عملية المنطق تتبع المنطق "يتم تشغيله مرة واحدة على الأقل" ، فيجب إكمال استدعاء الوظيفة لإعادة تعيين السابق إلى الوقت الحالي. باختصار ، هو في الواقع الحالي مقارنة مع المرة القادمة.
/*** طريقة اختناق الوظيفة* param function fn funct function function* param number تأخير كم من الوقت هو تأخير* param على الأقل كم من الوقت يتم تشغيله* طريقة وظيفة return لتأخير تنفيذ*/var throttle = function (fn ، delay ، على الأقل) {var timer = null ؛ var السابق = فارغ ؛ Return Function () {var now = +new Date () ؛ إذا (! السابق) السابق = الآن ؛ إذا (الآن - سابق> على الأقل) {fn () ؛ // إعادة تعيين وقت البدء الأخير حتى وقت الانتهاء من هذا الوقت السابق = الآن ؛ } آخر {cleartimeout (timer) ؛ timer = setTimeOut (function () {fn () ؛} ، delay) ؛ }}} ؛يمارس:
نحاكي مشهدًا من الاختناق عند تمرير نافذة ، أي عندما يقوم المستخدم بتمرير الصفحة لأسفل ، نحتاج إلى اختناق بعض الأساليب ، مثل: حساب موضع DOM ، وما إلى ذلك ، والذي يتطلب تشغيل عناصر DOM مستمرة.
الرمز الكامل كما يلي:
<! doctype html> <html lang = "en"> <head> <meta charset = "utf-8"> <title> Throttle </title> </head> <body> <div style = "height: 5000px"> <div id = "demo" style = "fump ؛" document.getElementById ('Demo') ؛ وظيفة testfn () {demo.innerhtml += 'testfn كان يسمى " +++ count +' time <br> '؛} var throttle = function (fn ، delay ، على الأقل) {var timer = null ؛ var السابق = فارغ ؛ Return Function () {var now = +new Date () ؛ إذا (! السابق) السابق = الآن ؛ if (على الأقل && الآن - سابق> على الأقل) {fn () ؛ // إعادة تعيين وقت البدء الأخير حتى وقت الانتهاء من هذا الوقت السابق = الآن ؛ ClearTimeout (مؤقت) ؛ } آخر {cleartimeout (timer) ؛ timer = setTimeOut (function () {fn () ؛ previce = null ؛} ، Delay) ؛ }}}} ؛ window.onscroll = خنق (testfn ، 200) ؛ // window.onscroll = Throttle (testfn ، 500 ، 1000) ؛ </script> </body> </html>نستخدم حالتين لاختبار التأثير ، وهما إضافة ما لا يقل عن تشغيل على الأقل على الأقل وليس إضافة:
// case 1window.onscroll = Throttle (testfn ، 200) ؛ // case 2window.onscroll = Throttle (testfn ، 200 ، 500) ؛
تتجلى الحالة 1 على النحو التالي: لن يتم استدعاء testfn أثناء عملية التمرير للصفحة (لا يمكن إيقافها) ، وسيتم استدعاؤها مرة واحدة حتى يتوقف ، مما يعني أنه يتم تنفيذ آخر وقت في الخانق ، كما هو موضح في الشكل:
تتجلى الحالة 2 على النحو التالي: أثناء عملية التمرير في الصفحة (لا يمكن إيقافها) ، سيتم تأخير TestFN بمقدار 500 مللي ثانية لأول مرة (من منطق التأخير على الأقل) ، ثم يتم تنفيذها على الأقل كل 500 مللي ثانية. التأثير كما هو موضح في الشكل
كما هو موضح أعلاه ، تم تقديم التأثيرات التي نريد تحقيقها وتقديم أمثلة. آمل أن يكون ذلك مفيدًا للأصدقاء المحتاجين. يمكن للقراء التفكير في بعض التحسينات المساعدة اللاحقة بأنفسهم ، مثل: وظيفة هذا الإشارة ، وتوفير قيمة الإرجاع ، وما إلى ذلك ، على أي حال ، من الرائع فهم هذه العملية بعناية!