管理頁面的 setTimeout&setInterval
來源:凹凸實驗室
aotu.io/notes/2017/09/25/manage-setTimeout-an-setInterval/
在管理 setTimeout & setInterval 這兩個 APIs 時,筆者通常會在頂級(全局)作用域創建一個叫 timer 的對象,在它下面有兩個數組成員 —— ,用它們來分別存儲需要管理的 setTimeoutID / setIntervalID。如下:
vartimer={
sto:[],
siv:[]
};
在使用 setTimeout / setInterval 的時候,這樣調用:
// 標記 setTimeoutID
setTimeout(function(){console.log("3s")},3000);
);
// 標記 setIntervalID
setInterval(function(){console.log("1s")},1000)
);
在頁面需要 clearTimeout clearInterval 的時候,這樣調用:
// 批量清除 setTimeout
// 批量清除 setInterval
暫停 & 恢復
近段時間,筆者發現很多業務都需要「暫停」和「恢復」setTimeout & setInterval 的功能,而僅靠原生的四個 APIs(setTimeout / setIntervale / clearTimeout / clearInterval)是不夠用的。於是,筆者對 timer 進行了擴展,使它具備了「暫停」和「恢復」的功能,如下:
// 暫停所有的 setTimeout & setInterval
timer.pause();
// 恢復所有的 setTimeout & setInterval
timer.resume();
擴展後的 timer對象下面掛載6個基礎的 APIs。
setTimeout
setInterval
clearTimeout
clearInterval
pause
resume
使用 timer.set* & timer.clear* 來代替原生的 set* & clear*。筆者把擴展後的 timer 託管在 GitHub 倉庫上,有興趣的同學可以移步:https://github.com/leeenx/timer
CreateJS 的啟發
在使用 CreateJS 開發一些項目的過程中,筆者發現通過設置 createjs.Ticker.paused = true / false,可以暫停/恢復 createjs.Tween 上的動畫。於是筆者借用 createjs.Tween 模擬了 setTimeout & setInterval 的功能,如下:
// setTimeout
createjs.setTimeout=function(fn,delay){
createjs.Tween.get().wait(delay).call(fn);
}
//setInterval
createjs.setInterval=function(fn,delay){
createjs.Tween.get().wait(delay).call(fn).loop=1;
}
具體的代碼筆者託管在:createjs.timer(https://github.com/leeenx/createjs.timer)。
其實就是在 createjs 對象下掛載四個 APIs:
setTimeout
setInterval
clearTimeout
clearInterval
使用方法與原生的 setTimeout & setInterval 一樣,如下:
letsiv=createjs.setInterval(()=>console.log("1s"),1000);
createjs.setTimeout(()=>createjs.clearInterval(siv),5000);
時間軸驅動的 timer
createjs.timer 在 CreateJS 項目的開發給筆者帶來了極大的便利,但是它必須依賴 createjs.Tween 模塊。於是筆者就在思考能否創建一個跟第三方框架無關並且又可以在第三方框架上使用的 timer。
createjs.Ticker.paused 為什麼能暫停 createjs.Tween 上的動畫的?
createjs.Tween 中每一個動畫都有一條自己的時間軸,這條時間軸是通過 createjs.Ticker 來驅動的;當 createjs.Ticker 被暫停後,createjs.Tween 中的每個動畫的時間軸也會失去動力而暫停下來。
createjs.Ticker 的作用是提供一個刷新 canvas 畫面幀頻,通常是使用 requestAnimationFrame or setInterval 來實現的。如果 timer 內部存在一條時間軸,這條時間軸由第三方驅動,那麼 timer 就可以與第三方框架狀態同步了。
筆者是這樣設計 timer 的結構:
queue —— 存放 setTimeout or setInterval 的隊列;
updateQueue —— 驅動 queue 的內部 API;
update —— 外部介面,用於對接第三方 Ticker。
實現的偽代碼如下:
/*
@queue 成員的結構如下:
{
fn: fn, // 回調函數
type: "timeout or interval", // 類型
elapsed: 0, // 時間軸進度
delay: delay // 目標時長
}
*/
letqueue=newMap();
functionupdateQueue(delta){
queue.forEach((item,id)=>{
item.elapsed+=delta;
if(item.elapsed>=item.delay){
item.fn();
// 從 queue 中刪除 setTimeout 成員,interval 成員繼續循環
item.type==="timeout"?delete(id):(item.elapsed=);
}
});
}
// 對外介面
this.update=function(delta){
updateQueue(delta);
}
timer 的具體實現可以參考:https://github.com/leeenx/es6-utils#timer
timer 與 CreateJS 一起使用:
// es6 代碼
import timerfrom ./modules/timer ;
// 統一 ticker
createjs.Ticker.addEventListener("tick",function(e){
e.pausedtimer.update(e.delta);
});
timer 與 PIXI 一起使用:
// es6 代碼
import timerfrom ./modules/timer ;
// 統一 ticker
app.ticker.add("tick",function(){
timer.update(app.ticker.elapsedMS);
});
附上 PIXI 的線上 DEMO,二維碼如下:
總結
感謝閱讀完本文章的讀者。本文僅代表個人觀點,希望能幫助到有相關問題的朋友,如果本文有不妥之處請不吝賜教。
看完本文有收穫?請轉發分享給更多人
關注「前端大全」,提升前端技能
![](https://pic.pimg.tw/zzuyanan/1488615166-1259157397.png)
![](https://pic.pimg.tw/zzuyanan/1482887990-2595557020.jpg)
※為什麼我們要做三份 Webpack 配置文件
※Web 的現狀:網頁性能提升指南
※你知道URL、URI和URN三者之間的區別嗎?
※V8 內存分配與垃圾回收
※2000塊都沒人的蘋果SE
TAG:前端大全 |