Underscore: الاقتراح: _.debounce و _.throttle يأخذان معلمات إضافية لكيفية دمج الوسيطات

تم إنشاؤها على ٢٢ سبتمبر ٢٠١١  ·  11تعليقات  ·  مصدر: jashkenas/underscore

إذا استخدمت _.debounce () لإنشاء دالة debounce ثم استدعيتها 3 مرات متتالية مع 3 مجموعات مختلفة من الوسيطات ، ثم (اعتبارًا من الإصدار 1.1.7) سيتم استدعاء وظيفة الحمولة المغلفة أخيرًا باستخدام الوسيطات المحددة بواسطة الاستدعاء الثالث - هذا هو يتم تجاهل الوسيطتين الأولى والثانية.

على الرغم من أن هذا غالبًا ما يكون صالحًا (وما يفعله عادةً إلغاء المفاتيح ، ومن ثم فهو افتراضي معقول) أجد نفسي أرغب في استخدام debounce لتجميع الحجج ، على سبيل المثال لدي مكالمة AJAX يمكنها الحصول على مفاتيح متعددة في وقت واحد ، لذلك أستخدم debounce للتخزين المؤقت مفاتيح التشغيل لمدة ثانية ثم إصدار طلب مشترك.

لذا فإن اقتراحي هو أن debounce يأخذ الوسيطة الثالثة "المدمجة" الاختيارية التي سيتم استدعاؤها بـ 2 args ،

  • الأول هو قائمة args المتراكمة حتى الآن (ربما غير محدد - أي لا توجد قائمة عند الاتصال الأول)
  • الثاني هو قائمة args لآخر مكالمة (ربما تكون قائمة فارغة)
    ويعيد القائمة الجديدة للوضعيات المتراكمة. عندما يتم استدعاء وظيفة الحمولة ، يتم مسح قائمة args المتراكمة.

إذا لم يتم تمرير أي قيمة للمعامل المدمج ، فإن الدمج الافتراضي يحافظ على السلوك الحالي
function(acc, newargs) { return newargs; }
ولكن يمكنك أيضًا أن تقرر استخدام المجموعة الأولى من الوسائط
function(acc, newargs) { return acc || newargs; }
أو ما أريد القيام به هو ببساطة إلحاق جميع الحجج
function(acc,newargs) { return (acc || []).concat(newargs); }
وبالطبع قد يرغب الآخرون في فعل شيء أفضل

قد يتطلب ذلك التغيير التالي لوظيفة الحد الداخلي

  // Internal function used to implement `_.throttle` and `_.debounce`.
  var limit = function(func, wait, debounce, combine) {
    var timeout, allargs;
    return function() {
      var context = this;
      allargs = combine(allargs,  slice.call(arguments,0))
      var throttler = function() {
        timeout = null;
        var args = allargs;
        allargs = undefined;
        func.apply(context, args);
      };
      if (debounce) clearTimeout(timeout);
      if (debounce || !timeout) timeout = setTimeout(throttler, wait);
    };
  };

ثم تغيير للإنزال للقبول وتمرير الوسيطة الجديدة بالقيمة الافتراضية إذا لم يتم تحديدها.

  _.debounce = function(func, wait, combine) {
    return limit(func, wait, true, combine || function(acc,newargs) { return newargs; });
  };

تستخدم وظيفة الخانق المقابلة حاليًا المجموعة الأولى من الوسائط وحدها (يتجاهل الخانق بشكل فعال المكالمات التي تحدث في غضون مللي ثانية من المكالمة الأولى ويستخدم مجموعة الاستدعاء الأولى من args ، ويتجاهل debounce بشكل فعال الكل ما عدا المكالمة الأخيرة في تسلسل يحدث خلال فترة الانتظار من بعضها البعض) ، لذلك أقترح ما يلي للحفاظ مرة أخرى على السلوك الافتراضي الحالي

  _.throttle = function(func, wait, combine) {
    return limit(func, wait, false, combine || function(acc,newargs) { return acc || newargs; });
  };

قد يبدو هذا هو الطريقة الأسهل والأكثر عمومية لتحقيق هذه الوظيفة بدون أغلفة مفرطة للحفاظ على قوائم الوسائط ، ولكن سأكون مهتمًا بمعرفة ما إذا كانت هناك طريقة سهلة لتحقيق ذلك دون تغيير الشرطة السفلية.

enhancement wontfix

التعليق الأكثر فائدة

حسنًا ، ليس للاستمرار في الضجيج ، ولكن في حالة نظر أي شخص إلى هذا في وقت ما لاحقًا وتساءل عن كيفية القيام بالمثل ، فقد اكتشفت أن هذا كان حول أنظف طريقة دون تعديل التنبيه نفسه (أقوم بإضافته إلى الكائن ، وقد لا يفضل الآخرون ذلك) ل)

_.mixin({
  debounceReduce: function(func, wait, combine) {
    var allargs,
        context,
        wrapper = _.debounce(function() {
            var args = allargs;
            allargs = undefined;
            func.apply(context, args);
        }, wait);
        return function() {
            context = this;
            allargs = combine.apply(context, [allargs,  Array.prototype.slice.call(arguments,0)]);
            wrapper();
        };
    }
})

هذا يعطي دالة مرفوضة والتي يتم تقليل وسيطاتها بواسطة وظيفة الجمع ، على سبيل المثال ،

  delayLog = _.debounceReduce(function() { console.log(arguments); }, 5000, 
                              function(acc,args) { return (acc || []).concat(args); });
  delayLog(3,4);
  delayLog(7,8,9);

ستستدعي بعد ثوانٍ console.log مع المصفوفة [3،4،7،8،9]

ال 11 كومينتر

بالتعليق على اقتراحي الخاص ، يجب أن تحدد دعوة الدمج () نفس سياق وظيفة الحمولة ، وبالتالي

allargs = combine.apply(this, [allargs, slice.call(arguments,0)])

في حالة احتياج الوسيطات للوصول إلى كائن السياق ....

الآن يجب أن تكون ثابتة على الماجستير. يجب أن يعرض throttle السلوك الصحيح حيث يستخدم دائمًا أحدث نسخة من الوسائط الخاصة بك ، ويتم إطلاقه مرة واحدة على الفور ، وكل N ثانية بعد ذلك ... ويعيد تعيين نفسه N ثانية بعد ذلك حدث آخر زناد زائدة.

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

آه ، أنت على حق. تعد الوسائط المتراكمة خارج نطاق الشرطة السفلية - لا تتردد في تخزين بياناتك المتراكمة في مكان جيد خارج الدالتين _.throttle و _.debounce .

هذا أمر مؤسف ، أعتبر أن debounce هو نوع من أضعاف اليسار (تقليل) على مكالمات متعددة مع مهلة ومن ثم المجمع ... لكنها مكالمتك :)

حسنًا ، ليس للاستمرار في الضجيج ، ولكن في حالة نظر أي شخص إلى هذا في وقت ما لاحقًا وتساءل عن كيفية القيام بالمثل ، فقد اكتشفت أن هذا كان حول أنظف طريقة دون تعديل التنبيه نفسه (أقوم بإضافته إلى الكائن ، وقد لا يفضل الآخرون ذلك) ل)

_.mixin({
  debounceReduce: function(func, wait, combine) {
    var allargs,
        context,
        wrapper = _.debounce(function() {
            var args = allargs;
            allargs = undefined;
            func.apply(context, args);
        }, wait);
        return function() {
            context = this;
            allargs = combine.apply(context, [allargs,  Array.prototype.slice.call(arguments,0)]);
            wrapper();
        };
    }
})

هذا يعطي دالة مرفوضة والتي يتم تقليل وسيطاتها بواسطة وظيفة الجمع ، على سبيل المثال ،

  delayLog = _.debounceReduce(function() { console.log(arguments); }, 5000, 
                              function(acc,args) { return (acc || []).concat(args); });
  delayLog(3,4);
  delayLog(7,8,9);

ستستدعي بعد ثوانٍ console.log مع المصفوفة [3،4،7،8،9]

schmerg - يبدو هذا مفيدًا للغاية. هل أنت على استعداد لترخيص هذا الرمز بموجب ترخيص MIT؟ (ستكفي "نعم"!)

markjaquith شيء أكيد - نعم. سعيد ل...

إذا أتى أي شخص وأراد إصدار js الحديث المحدث / المعلق لما سبق:

_.mixin({
  debounceReduce(func, wait, combine) {
    let allArgs; // accumulator for args across calls

    // normally-debounced fn that we will call later with the accumulated args
    const wrapper = _.debounce(() => func(allArgs), wait);

    // what we actually return is this function which will really just add the new args to
    // allArgs using the combine fn
    return (...args) => {
      allArgs = combine(allArgs,  [...args]);
      wrapper();
    };
  },
});

kmannislands مرحبًا ، لم يتم إعادة تعيين نسختك allArgs داخل wrapper() ، لذا فإن المكالمات اللاحقة إلى func() تحصل على دفعات تاريخية من args بالإضافة إلى الدُفعة الحالية.

ألا يجب أن يكون:

const wrapper = _.debounce(() => {
    const args = allArgs;
    allArgs = undefined;
    func(args);
}, wait);

تضمين التغريدة

يختلف أيضًا func( args ) عن الإصدار الأصلي الذي يستخدم func.apply(context, args); .
بالنسبة للأول ، يتم استخدام args كما هو الحال في الهدف func() ، بينما في الأحدث _ (الكود الأصلي) _ تحتاج إلى استخدام إما arguments في وظيفة عادية أو ( ...args ) في دالة es6 للسهم السميك.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات