w3ctech

(译)使用setimmediate实现可伸缩执行的脚本

原文地址:http://www.nczonline.net/blog/2011/09/19/script-yielding-with-setimmediate/

本文由小豪翻译

看过我对JavaScript 性能优化相关的讨论的同学们一定很了解我的一个癖好,就是将一大段的script分解成多个块来执行。通过使用setTimeout(),你可以去改变特定代码执行的时间,从而做到让UI现场执行已经在队列里的任务。比如,你可以通过这样的方式把要执行的代码在50ms后加到UI线程队列里:

setTimeout(function(){
   //do  something
}, 50)

那么,在50ms后,这个函数就会被添加到队列里,并在轮到它的时候执行。调用setTimeout()方法可以允许当前的JavaScript任务完成从而下一个UI更新可以顺利进行。

虽然我一直很支持使用setTimeout()来提高性能,但是还是存在几个问题。第一个并且是最重要的问题是不同的浏览器有着不一样的时间精确度。IE8和更早的IE的时间精确度是15.6ms,而IE9,或者更新的浏览器,还有chrome的时间精确度已经到达4ms。所有的浏览器都强制给setTimeout设置了一个最低延迟值,所以setTimeout(fn, 0)实际上在大于0ms的时间之后才会执行,具体取决于对应的时间精确度。

另一个是电源使用的问题。管理时间关系到笔记本或者手机的电池使用。Chrome曾经尝试把时间精确度降低到1ms,结果发现会增加笔记本电池的损耗。最后还是觉得把时间精确度设置回4ms。其他浏览器也做过类似的尝试,不过许多油门计时器分辨率为1s。微软发现时间精确度为1ms的时候,电池的使用时间会降低25%。实际上,IE9会判断笔记本是否在使用电池的情况下运行,如果是电池,则时间精确度为15.6ms,如果是直接插的电源则时间精确度会降低到4ms。

来自W3C Web Performance Working Group的一个方案“Efficient Script Yielding”,定义了一个新的函数去实现脚本的分块执行的setImmediate()方法。 这个方法接收一个函数作为参数,它可以让这个函数在UI线程空闲的时候执行。基本的用法:

var id = setImmediate(function(){
    //do something
});

setImmediate()函数会返回一个id,这个id可以通过clearImmediate()方法来取消这个过程。

我们也可以给它传递一些参数

setImmediate(function(doc, win){
    //do something
}, document, window);

用这个方式来传递可选的参数意味着你不需要总是使用一个闭包来让函数包含一些有用的信息。

setImmediate()可以让浏览器不需要去管理进程的定时器。不需要去等待更耗电的系统中断,浏览器只需要等待UI队列空闲,然后把新的JavaScript任务插入进去。Node.js的开发者会比较容易理解这个问题,因为process.nextTick()在自己的环境里做了相同的事情。

现在只有ie10支持这个方法,而且因为还没有完全定下来,所以使用了msSetIntermediate()。IE10的Test Drive上也有一个setImmediate()的例子,展示了新方法带来的性能提升。这个例子使用一个延迟来排列一些数据,排序之后的状态会直接展示出来。

w3ctech微信

扫码关注w3ctech微信公众号

共收到0条回复