Jika saya menggunakan _.debounce() untuk membuat fungsi yang di-debounce dan kemudian memanggilnya 3 kali berturut-turut dengan 3 set argumen yang berbeda, maka (mulai v1.1.7) fungsi payload yang dibungkus akhirnya akan dipanggil dengan argumen yang ditentukan oleh Panggilan ke-3 - itu adalah argumen pertama dan kedua dibuang.
Meskipun ini sering valid (dan apa yang biasanya dilakukan oleh debounce kunci, karenanya merupakan default yang masuk akal) saya mendapati diri saya ingin menggunakan debounce untuk mengumpulkan argumen, misalnya saya memiliki panggilan AJAX yang bisa mendapatkan beberapa kunci sekaligus, jadi saya menggunakan debounce untuk buffer tombol up sebentar dan kemudian mengeluarkan permintaan gabungan.
Oleh karena itu saran saya adalah bahwa debounce mengambil argumen "gabungkan" ke-3 opsional yang akan dipanggil dengan 2 argumen,
Jika tidak ada nilai yang diteruskan untuk parameter kombinasi, kombinasi default mempertahankan perilaku yang ada
function(acc, newargs) { return newargs; }
tetapi Anda juga dapat memutuskan untuk menggunakan set argumen pertama
function(acc, newargs) { return acc || newargs; }
atau apa yang ingin saya lakukan hanyalah menambahkan semua argumen
function(acc,newargs) { return (acc || []).concat(newargs); }
dan tentu saja orang lain mungkin ingin melakukan sesuatu yang lebih menarik
Ini akan membutuhkan perubahan berikut pada fungsi batas internal:
// 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);
};
};
dan kemudian perubahan ke debounce untuk menerima dan meneruskan argumen baru dengan nilai default jika tidak ditentukan.
_.debounce = function(func, wait, combine) {
return limit(func, wait, true, combine || function(acc,newargs) { return newargs; });
};
Fungsi throttle yang sesuai saat ini menggunakan set argumen pertama saja (throttle secara efektif mengabaikan panggilan yang terjadi dalam menunggu milidetik dari panggilan pertama dan menggunakan set argumen panggilan pertama, debounce secara efektif mengabaikan semua kecuali panggilan terakhir dalam urutan yang terjadi dalam periode tunggu satu sama lain), jadi saya sarankan di bawah ini untuk kembali mempertahankan perilaku default saat ini
_.throttle = function(func, wait, combine) {
return limit(func, wait, false, combine || function(acc,newargs) { return acc || newargs; });
};
Tampaknya ini cara termudah dan paling umum untuk mencapai fungsi ini tanpa pembungkus berlebihan untuk mempertahankan daftar argumen, tetapi saya tertarik untuk mengetahui apakah ada cara mudah untuk mencapai ini tanpa mengubah garis bawah.
Mengomentari saran saya sendiri, panggilan ke combine() harus menentukan konteks yang sama dengan fungsi payload, karenanya
allargs = combine.apply(this, [allargs, slice.call(arguments,0)])
jika argumen perlu mengakses objek konteks ....
Sekarang harus diperbaiki pada master. throttle
harus menunjukkan perilaku yang benar di mana ia selalu menggunakan salinan terbaru dari argumen Anda, langsung aktif sekali, dan setiap N
detik setelahnya ... dan me-reset sendiri N
detik setelahnya pemicu trailing terakhir telah terjadi.
Saya pikir komentar dekat Anda berlaku untuk masalah lain (mungkin #170), karena masalah yang diangkat oleh permintaan ini masih berlaku pada master.
Masih tidak ada cara mudah untuk mendebounce atau mencekik argumen akumulasi dari panggilan yang sedang digabungkan, dan saya masih berpikir itu adalah tambahan opsional yang berguna yang membuat perilaku default tidak berubah ketika argumen penggabungan opsional tidak ditentukan.
Anda benar. Mengumpulkan argumen berada di luar cakupan Garis Bawah -- jangan ragu untuk menyimpan data yang terkumpul di tempat yang baik di luar fungsi _.throttle
dan _.debounce
.
Sayang sekali, saya menganggap debounce sebagai semacam flip-kiri (mengurangi) lebih dari beberapa panggilan dengan batas waktu maka akumulator ... tapi itu panggilan Anda :)
OK, bukan untuk terus menggedor, tetapi jika ada yang melihat ini nanti dan bertanya-tanya bagaimana melakukan hal yang sama, saya pikir ini adalah cara terbersih tanpa memodifikasi debounce itu sendiri (saya menambahkannya ke objek _, orang lain mungkin lebih suka tidak ke)
_.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();
};
}
})
Ini memberikan fungsi debouncing yang argumennya dikurangi dengan fungsi kombinasikan, misalnya,
delayLog = _.debounceReduce(function() { console.log(arguments); }, 5000,
function(acc,args) { return (acc || []).concat(args); });
delayLog(3,4);
delayLog(7,8,9);
akan beberapa detik kemudian memanggil console.log dengan array [3,4,7,8,9]
@schmerg — ini terlihat sangat berguna. Apakah Anda bersedia melisensikan kode itu di bawah lisensi MIT? (Jawaban "ya" sudah cukup!)
@markjaquith Tentu saja - ya. Senang...
Jika ada yang datang dan ingin memperbarui/mengkomentari versi js modern di atas:
_.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 Hei, versi Anda tidak mengatur ulang allArgs
di dalam wrapper()
, jadi panggilan berikutnya ke func()
mendapatkan kumpulan argumen historis serta kumpulan saat ini.
Bukankah seharusnya:
const wrapper = _.debounce(() => {
const args = allArgs;
allArgs = undefined;
func(args);
}, wait);
@markjaquith +1
Juga func( args )
berbeda dari versi asli yang menggunakan func.apply(context, args);
.
Untuk yang pertama, args
digunakan seperti pada target func()
, sedangkan di _(kode asli)_ selanjutnya Anda perlu menggunakan arguments
dalam fungsi normal atau ( ...args )
dalam fungsi panah gemuk es6.
Komentar yang paling membantu
OK, bukan untuk terus menggedor, tetapi jika ada yang melihat ini nanti dan bertanya-tanya bagaimana melakukan hal yang sama, saya pikir ini adalah cara terbersih tanpa memodifikasi debounce itu sendiri (saya menambahkannya ke objek _, orang lain mungkin lebih suka tidak ke)
Ini memberikan fungsi debouncing yang argumennya dikurangi dengan fungsi kombinasikan, misalnya,
akan beberapa detik kemudian memanggil console.log dengan array [3,4,7,8,9]