Web 开发人员版本 — 最后更新于 2024年9月12日
使用 setTimeout()
和 setInterval()
方法,作者可以安排基于定时器的回调函数。
id = self.setTimeout(handler [, timeout [, ...arguments ] ])
安排在 timeout 毫秒后运行 handler 的超时。任何 arguments 都将直接传递给 handler。
id = self.setTimeout(code [, timeout ])
安排在 timeout 毫秒后编译并运行 code 的超时。
self.clearTimeout(id)
取消使用 setTimeout()
或 setInterval()
设置的由 id 标识的超时。
id = self.setInterval(handler [, timeout [, ...arguments ] ])
安排每隔 timeout 毫秒运行 handler 的超时。任何 arguments 都将直接传递给 handler。
id = self.setInterval(code [, timeout ])
安排每隔 timeout 毫秒编译并运行 code 的超时。
self.clearInterval(id)
取消使用 setInterval()
或 setTimeout()
设置的由 id 标识的超时。
定时器可以嵌套;但是,在五个这样的嵌套定时器之后,间隔将强制设置为至少四毫秒。
此 API 无法保证定时器将按计划准确运行。由于 CPU 负载、其他任务等原因造成的延迟是预料之中的。
要连续运行几个毫秒的任务而没有任何延迟,同时仍然向浏览器让出控制权以避免使用户界面饿死(并避免浏览器因占用 CPU 而终止脚本),只需在执行工作之前排队下一个定时器即可
function doExpensiveWork() {
var done = false ;
// ...
// this part of the function takes up to five milliseconds
// set done to true if we're done
// ...
return done;
}
function rescheduleWork() {
var id = setTimeout( rescheduleWork, 0 ); // preschedule next iteration
if ( doExpensiveWork())
clearTimeout( id); // clear the timeout if we don't need it
}
function scheduleWork() {
setTimeout( rescheduleWork, 0 );
}
scheduleWork(); // queues a task to do lots of work
所有当前引擎均支持。
self.queueMicrotask(callback)
将一个 微任务 排队以运行给定的 callback。
queueMicrotask()
方法允许作者在 微任务队列 上安排回调函数。这允许他们的代码在 JavaScript 执行上下文栈 下一次为空时运行,这发生在所有当前正在执行的同步 JavaScript 代码都运行完成之后。这不会像使用例如 setTimeout(f, 0)
时那样将控制权让回 事件循环。
作者应该意识到,安排大量微任务与运行大量同步代码具有相同的性能问题。两者都会阻止浏览器执行自己的工作,例如渲染。在许多情况下,requestAnimationFrame()
或 requestIdleCallback()
是更好的选择。特别是,如果目标是在下一个渲染周期之前运行代码,那么这就是 requestAnimationFrame()
的用途。
从以下示例可以看出,理解 queueMicrotask()
的最佳方式是将其视为一种重新安排同步代码的机制,有效地将排队的代码放在当前正在执行的同步 JavaScript 代码运行完成之后。
使用 queueMicrotask()
最常见的原因是创建一致的顺序,即使在同步可用信息的情况下,也不引入不必要的延迟。
例如,考虑一个自定义元素触发 load
事件,该事件还维护先前加载数据的内部缓存。一个简单的实现可能如下所示
MyElement. prototype. loadData = function ( url) {
if ( this . _cache[ url]) {
this . _setData( this . _cache[ url]);
this . dispatchEvent( new Event( "load" ));
} else {
fetch( url). then( res => res. arrayBuffer()). then( data => {
this . _cache[ url] = data;
this . _setData( data);
this . dispatchEvent( new Event( "load" ));
});
}
};
但是,这个简单的实现存在问题,因为它会导致其用户体验不一致的行为。例如,如下代码
element. addEventListener( "load" , () => console. log( "loaded" ));
console. log( "1" );
element. loadData();
console. log( "2" );
有时会记录“1, 2, loaded”(如果需要获取数据),有时会记录“1, loaded, 2”(如果数据已缓存)。类似地,在调用 loadData()
之后,元素上是否设置数据将不一致。
为了获得一致的顺序,可以使用 queueMicrotask()
MyElement. prototype. loadData = function ( url) {
if ( this . _cache[ url]) {
queueMicrotask(() => {
this . _setData( this . _cache[ url]);
this . dispatchEvent( new Event( "load" ));
});
} else {
fetch( url). then( res => res. arrayBuffer()). then( data => {
this . _cache[ url] = data;
this . _setData( data);
this . dispatchEvent( new Event( "load" ));
});
}
};
通过实质上重新安排排队的代码使其位于 JavaScript 执行上下文栈 清空之后,这确保了元素状态的一致顺序和更新。
另一个有趣的 queueMicrotask()
用法是允许多个调用者非协调地“批量”处理工作。例如,考虑一个库函数,该函数希望尽快将数据发送到某个位置,但如果很容易避免,则不想发出多个网络请求。平衡这一点的一种方法如下所示
const queuedToSend = [];
function sendData( data) {
queuedToSend. push( data);
if ( queuedToSend. length === 1 ) {
queueMicrotask(() => {
const stringToSend = JSON. stringify( queuedToSend);
queuedToSend. length = 0 ;
fetch( "/endpoint" , stringToSend);
});
}
}
使用此架构,当前正在执行的同步 JavaScript 中对 sendData()
的多次后续调用将被批量组合到一个 fetch()
调用中,但没有中间的事件循环任务抢占获取(就像使用类似的代码并且改为使用 setTimeout()
时会发生的那样)。
window.alert(message)
显示带有给定消息的模态警报,并等待用户将其关闭。
result = window.confirm(message)
显示带有给定消息的模态确定/取消提示,等待用户将其关闭,如果用户单击确定则返回 true,如果用户单击取消则返回 false。
result = window.prompt(message [, default])
显示带有给定消息的模态文本控件提示,等待用户将其关闭,并返回用户输入的值。如果用户取消提示,则返回 null。如果存在第二个参数,则使用给定值作为默认值。
依赖于 任务 或 微任务 的逻辑,例如 媒体元素 加载其 媒体数据,在调用这些方法时会被暂停。
所有当前引擎均支持。
window.print()
提示用户打印页面。