(用于什么情況檐薯?)
(用setTimeout模擬setInterval)
一、setTimeout需要注意的地方
1、setTimeout共有4個參數(shù)
最后那兩個參數(shù)爆袍,將在1000毫秒之后回調(diào)函數(shù)執(zhí)行時松邪,作為回調(diào)函數(shù)的參數(shù)坞琴。
setTimeout(function(a,b){
console.log(a+b);
},1000,1,1);
2、被setTimeout推遲執(zhí)行的回調(diào)函數(shù)是在全局環(huán)境執(zhí)行逗抑,有可能不同于函數(shù)定義時的上下文環(huán)境
var x = 1;
var o = {
x: 2,
y: function(){
console.log(this.x);
}
};
// 回調(diào)函數(shù)的運行環(huán)境已經(jīng)變成了全局環(huán)境
setTimeout(o.y,1000); // 1
3剧辐、this問題
function User(login) {
this.login = login;
this.sayHi = function() {
console.log(this.login);
}
}
var user = new User('John');
// this指向全局
setTimeout(user.sayHi, 1000); // undefined
// 將user.sayHi放在函數(shù)中執(zhí)行
setTimeout(function() {
// this指向user
user.sayHi();
}, 1000) // John
二、setInterval的不足之處
1邮府、不去關(guān)心回調(diào)函數(shù)是否還在運行
在某些情況下荧关,函數(shù)可能需要比間隔時間更長的時間去完成執(zhí)行。比如說是用setInterval每隔5秒對遠端服務(wù)器進行輪詢褂傀,網(wǎng)絡(luò)延遲忍啤,服務(wù)器無響應(yīng)以及其他因素將會阻止請求按時按成。結(jié)果會導(dǎo)致返回一串無必要的排成隊列請求仙辟。
2同波、忽視錯誤
因為某些原因,setInterval調(diào)用的代碼中會出現(xiàn)一個錯誤欺嗤,但是代碼并不會中止執(zhí)行而是繼續(xù)執(zhí)行錯誤的代碼参萄。
3、缺乏靈活性
除了前面提到的缺點之外煎饼,我非常希望setInterval方法能有一個表明執(zhí)行次數(shù)的參數(shù)而不是無休止的執(zhí)行下去讹挎。
三、用setTimeout模擬setInterval
setTimeout(function(){
//do something
setTimeout(arguments.callee,interval);
},interval)
// 刷新股票
refreshTick = () => {
// 定時器 —— this.refreshTickInterval
this.refreshTickInterval = setTimeout(this.refreshTick, 250)
if (Object.keys(this.mixedTick).length !== 0) {
this.props.doSocketTicks(this.mixedTick)
// 刷新完吆玖,清空mixedTick
this.mixedTick = {}
}
}
// 注意unmount的時候要去除定時器
// componentWillUnmount() {
// 去除定時器
// clearTimeout(this.refreshTickInterval)
// }
四筒溃、例題
1、以下代碼有什么區(qū)別沾乘,各自輸出什么怜奖?
for (var i = 0; i < 10; ++i) {
setTimeout( function () {console.log(i)}, 0);
}
for (var i = 0; i < 10; ++i) {
setTimeout((function () {console.log(i)})(), 0);
}
解:2、以下代碼執(zhí)行后翅阵,輸出什么歪玲?
setTimeout(function () {
console.log(1);
}, 0);
Promise.resolve(function () {
console.log(2);
})
new Promise(function (resolve) {
console.log(3);
});
console.log(4);
解:輸出3 4 undefined 1
js中的事件執(zhí)行主要分為兩個任務(wù)類型 macro task以及micro task 也就是宏仁務(wù)和微任務(wù)
宏仁務(wù):script(全局任務(wù))迁央,setTimeout ,setInterval 滥崩,setImmediate 岖圈,I/O ,UI rendering
微任務(wù):process.nextTick, promise, Object.observer, MutationObserver
執(zhí)行順序為 script先進入函數(shù)調(diào)用棧钙皮,
然后執(zhí)行遇到任何其他宏仁務(wù)蜂科,比如遇到了setTimeout,就把setTimeout放進宏仁務(wù)隊列中短条,遇到了微任務(wù)就放入微任務(wù)隊列中导匣,
等到函數(shù)調(diào)用棧的所有內(nèi)容出棧后 然后執(zhí)行微任務(wù)隊列,
然后再回頭執(zhí)行宏仁務(wù)隊列再進入函數(shù)調(diào)用棧再執(zhí)行微任務(wù)隊列茸时,直到宏仁務(wù)隊列執(zhí)行完畢
//異步隊列:遇到setTimeout贡定,放入宏仁務(wù)隊列
setTimeout(function () {
console.log(1);
}, 0);
//寫法錯誤:遇到promise,放入微任務(wù)隊列屹蚊,在主task之后立刻執(zhí)行
Promise.resolve(function () {
console.log(2);
})
//立即執(zhí)行:這里雖然遇到了promise厕氨,但是是用new聲明的,也就是立即執(zhí)行汹粤,所以會先輸出3
new Promise(function (resolve) {
console.log(3);
});
//立即執(zhí)行:第二輸出4
console.log(4);
// 需要注意的是那個undefined并不是微任務(wù)輸出的命斧,
// 而是console.log(4)輸出的,具體可以控制臺測試
// 然后執(zhí)行微任務(wù)嘱兼,這個微任務(wù)并沒有調(diào)用国葬,所以也不會執(zhí)行,
// 然后執(zhí)行宏仁務(wù)隊列中的setTimeout芹壕,輸出1