setTimeout、setInterval。其第三个参数和this的讨论,超时嵌套和内存泄漏

来源:互联网 发布:js回调函数的返回值 编辑:程序博客网 时间:2024/06/11 19:13


setTimeout和setInterval函数的第三个参数本来只是定义语言类型,后来在非IE浏览器下支持传递参数,并且在不同浏览器下支持的不同。

原来的setTimeout函数定义:
var timeoutID = window.setTimeout(func, delay[, lang]);

在Chrome和FF下定义被修改:
var timeoutID = window.setTimeout(func, delay, [param1, param2, …]);
var timeoutID = window.setTimeout(code, delay);

IE:不支持第三个参数。
Chrome:接受的参数=传递的参数个数。
FF:接受的参数=传递的参数个数+1

具体可参看:https://developer.mozilla.org/zh-CN/docs/DOM/window.setTimeout

(function (w) {
//ie传入第三个参数
if (! + [1, ]) { //除IE外,!+[1,]都是返回false
(function (overrideFn) {
//overrideFn应改为wrapCall
w.setTimeout = overrideFn(w.setTimeout);
w.setInterval = overrideFn(w.setInterval);
})(function (originalFn) {//包装函数,仅供上二行调用,只一个参数一个类setInterval返回函数
originalFn.isPolyfill = true;//fix ie9–
//注意return替换函数,而非调用返回值。返回真正要被替换的setTimeout,setInterval
return function (code, delay) {//这才是真正的overrideFn
var me = this,//fix: 激活code所在的this作用域
args = Array.prototype.slice.call(arguments, 2);
return originalFn(function () {//这里才调用原API
if (typeof code == ‘string’) {
eval(code);
} else {
code.apply(me, args);
}
}, delay);
}
})
}
})(window);

现在可以测试一下:
myArray = [“zero”, “one”, “two”];
myArray.myMethod = function (sProperty) {
alert(arguments.length > 0 ? this[sProperty] : this);
};

setTimeout.call(myArray, myArray.myMethod, 1000);
setTimeout.call(myArray, myArray.myMethod, 1500, 2);
注意二点:还是得用call或apply;传给setTimeout的回调如果是字符串,则第三参数没有意义!
上面代码的另外一点不足之处,就是原setTimeout的“指针”没有保存到return function (code, delay) {//这才是真正的overrideFn

这行代码后的数据中,不过考虑js也不是原生支持OO,这点缺憾还是可以接受的!

现在,我要重点说说setTimeout的超时调用,特别是在循环中

while (!flag) {
//等待异步完成==>代码意图:每30毫秒轮询异步完成标志,未完成则等待,让出执行权响应用户事件,意图实现类似sleep效果
setTimeout(null, 30);
}

上面代码看上去好像没问题,每30毫秒轮询异步完成标志~但是Js是单线程的
所以,这就是段死循环,不停的创建超时计时器,其它代码没法变更完成标志!一二分钟后就挂了!解决方法,就是回调!

可以用定时器setInterval在回调函数中轮询异步完成标志。但最好的办法还是在异步操作中设置好回调!JS也就这点令人烦,有时大量的回调嵌套三四层,这样OO代码实现就有点烦琐了!

最后点一下,JS引擎单线程,队列式执行:
setTimeout(fn, 0);//fn不会马上执行,而是得先前的执行队列完成才能执行

HTML5中规定:setTimeout最少超时4ms

阅读全文
0 0
原创粉丝点击