防抖与节流
防抖
触发多次的事件都归并为一次事件在给定的时间内进行触发
document.onmousemove = _.debounce(()=> {
console.log(1)
},
1000,
true // 首次立即执行
)
节流
在一次事件中,按给定的时间进行分段触发
document.onmousemove = _.throttle(()=> {
console.log(1)
},1000,{
leading:false, // 首次立即执行
trailing:true // 最后一次不触发
})
宏任务和微任务
异步任务需要适当的管理。为此,ECMA 标准规定了一个内部队列 PromiseJobs,通常被称为“微任务队列(microtask queue)”(ES8 术语)。当一个 promise 准备就绪时,它的 .then/catch/finally 处理程序(handler)就会被放入队列中:但是它们不会立即被执行。当 JavaScript 引擎执行完当前的代码,它会从队列中获取任务并执行它。
每个宏任务之后,引擎会立即执行微任务队列中的所有任务,然后再执行其他的宏任务,或渲染,或进行其他任何操作。
setTimeout(() => alert("timeout"));
Promise.resolve()
.then(() => alert("promise"));
alert("code");
code 首先显示,因为它是常规的同步调用。
promise 第二个出现,因为 then 会通过微任务队列,并在当前代码之后执行。
timeout 最后显示,因为它是一个宏任务。
微任务防抖
const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof navigator !== 'undefined'
const supportsMicroTasks = isBrowser && window.Promise
function microtaskDebounce(fn) {
let called = false
return () => {
if (called) {
return
}
called = true
window.Promise.resolve().then(() => {
called = false
fn()
})
}
}
const timeoutDuration = (function(){
const longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
for (let i = 0; i < longerTimeoutBrowsers.length; i += 1) {
if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
return 1;
}
}
return 0;
}());
function taskDebounce(fn) {
let scheduled = false;
return () => {
if (!scheduled) {
scheduled = true;
setTimeout(() => {
scheduled = false;
fn();
}, timeoutDuration);
}
};
}
requestAnimationFrame(supportsMicroTasks ? microTaskDebounce : taskDebounce)