如果要异步执行一个函数,我们最先想到的方法肯定会是 setTimeout
例如:setTimeout(function( /* 1s 后做点什么 */){},1000}
那如果说要最快速地异步执行一个函数呢?
是否会是:
1 |
setTimeout(function( /* 尽快做点什么 */){},0} |
可惜的是,浏览器为了避免 setTimeout 嵌套可能出现卡死 ui 线程的情况,为 setTimeout 设置了最小的执行时间间隔,不同浏览器的最小执行时间间隔都不一样。chrome 下测试 setTimeout 0 的实际执行时间间隔大概在 12ms 左右。
那么如果想最快地异步执行一个函数,有没有什么可以提速的方法呢?
先来看看浏览器端,有哪些常用的异步执行方法
setImmediate:该方法去实现比 setTimeout 0 更快的异步执行,执行时间更接近 0ms,但是只有 IE/node 支持。
requestAnimationFrame:做动画循环的时候经常会用到这个方法,该方法只会在浏览器刷新 ui 的时候执行,刷新 ui 的频率最大一般为 60fps,所以 requestAnimationFrame 一般情况下比 setTimeout 0 更慢一些。
除了使用异步函数外,还有一些方法可以实现异步调用
利用 onmessage:
和 iframe 通信时常常会使用到 onmessage 方法,但是如果同一个 window postMessage 给自身,会怎样呢?其实也相当于异步执行了一个 function
例如:
1 2 3 |
var doSth = function(){} window.addEventListener("message", doSth, true); window.postMessage("", "*"); |
另外,还可以利用 script 标签,实现函数异步执行,例如:
1 2 3 |
var newScript = document.createElement("script"); newScript.onreadystatechange = doSth; document.documentElement.appendChild(newScript); |
把 script 添加到文档也会执行 onreadystatechange 但是该方法只能在 IE 下浏览器里使用。
那么 这几种方法,谁最快?
测试了一下,
chrome 下:
setImmediate:不可用。
setTimeout 0:12ms
onmessage:6ms
onreadystatechange:不支持
chrome 下,onmessage 比 setTimeout 0 更快。
firefox 下:
setImmediate:不可用。
setTimeout 0:7ms
onmessage:7ms
onreadystatechange:不支持
firefox 下,onmessage 和 setTimeout 0 速度相当。
IE9:
setImmediate:不可用。
setTimeout 0:11ms
onmessage:7ms 10ms
onreadystatechange:2ms
IE9 下,onreadystatechange 的时间比另外两者要快得多。
总体情况下,setImmediate < readystatechange < onmessage < setTimeout 0 < requestAnimationFrame
因此我们可以简单封装一个快速执行异步 function 的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var setZeroTimeout = (function(){ if(window.setImmediate){ //IE10+版本,使用原生setImmediate return window.setImmediate; } else if("onreadystatechange" in document.createElement("script")){ return function(){/* 使用onreadystatechange的版本 */} } else if(window.postMessage){ return function(){/* 使用onmessage的异步执行版本 */} } else { return window.setTimeout; } })(); |
rambo 2017 年 7 月 6 日
https://github.com/shahyar/setZeroTimeout-js/blob/master/setZeroTimeout.js 跟您第二个想法一样
tormahiri 2014 年 11 月 15 日
不错误的文章
Kpaxqin 2014 年 9 月 16 日
关于时钟还有个问题
在 chrome 下(其它浏览器还没测)
var i = 0;
setInterval(function(){
if (i == 10){ //每 1 秒输出一次当前
console.log(new Date());
i = 0;
}else{
i++;
}
}, 100)
切换其它标签页浏览一会儿,再切回,如下最后一条 console 打印,足足间隔了有接近 10 秒
似乎【在浏览其它标签页时,setInterval 被阻塞了】
Tue Sep 16 2014 11:35:32 GMT+0800 (中国标准时间) test.html:16
Tue Sep 16 2014 11:35:33 GMT+0800 (中国标准时间) test.html:16
Tue Sep 16 2014 11:35:35 GMT+0800 (中国标准时间) test.html:16
Tue Sep 16 2014 11:35:44 GMT+0800 (中国标准时间)
但是
setInterval(function(){
console.log(new Date());
}, 1000)
则不会有类似的问题
style 2014 年 7 月 17 日
5555555
style 2014 年 7 月 17 日
tttttt
style 2014 年 7 月 17 日
tttttttttttttt
fredshare 2014 年 6 月 25 日
都是毫秒级别的,何必如此计较
gdut-zdc 2014 年 3 月 24 日
博主,ui 线程卡死指的是两个任务同时进入到 ui 线程内,导致 ui 线程卡死吗?求指教啊,这里困扰了我好几天了,找了好些资料,陷入思维沼泽了。求搭救啊。能否回复一下呀..
gdut-zdc 2014 年 3 月 24 日
你好,你说的 “浏览器为了避免 setTimeout 嵌套可能出现卡死 ui 线程的情况,为 setTimeout 设置了最小的执行时间间隔” 这句话是怎么理解的?可否指教一下。
TAT.dmyang 2014 年 4 月 6 日
setTimeout 的延迟时间最短是 16ms,小于 10ms 会自动设置成 16ms
gdut-zdc 2014 年 3 月 22 日
用 settimeout 这种方法来模拟异步执行 javascript 并不是真正的异步执行。目前 javascript 并不支持多线程。
Kevin 2014 年 3 月 22 日
执行时间间隔用什么工具测试出来的
Sigma 2015 年 5 月 26 日
console.time(‘Hello’);
setTimeout(function(){
console.timeEnd(‘Hello’);
}, 0);
Hello: 1.098ms
javascript、jQuery学习系列文章 - ^styleYan 2014 年 3 月 13 日
[…] javascript 更快的异步执行 […]
TAT.Johnny 2014 年 3 月 8 日
看过一篇浏览器时钟精度的文章, 可以参考一下
http://www.ituring.com.cn/article/1828?q=settimeout
kazaff 2014 年 3 月 4 日
看了第一行就发现错了:
例如:setTimeout(function( /* 1s 后做点什么 */){},1000}
?
MiCoo 2014 年 3 月 5 日
瑕不掩瑜啦
krew 2014 年 3 月 17 日
哈哈,放错地了。。
Jack Works 2014 年 6 月 15 日
其实这样放也是可以执行的啊 = =
Sigma 2015 年 5 月 26 日
注释没问题,但括号没闭合。