如何存儲(chǔ)管理頁面 setTimeout & setInterval
在管理 setTimeout & setInterval 這兩個(gè) APIs 時(shí),筆者通常會(huì)在***(全局)作用域創(chuàng)建一個(gè)叫 timer 的對(duì)象,在它下面有兩個(gè)數(shù)組成員 —— {sto, siv},用它們來分別存儲(chǔ)需要管理的 setTimeoutID / setIntervalID。如下:
- var timer = {
- sto: [],
- siv: []
- };
在使用 setTimeout / setInterval 的時(shí)候,這樣調(diào)用:
- // 標(biāo)記 setTimeoutID
- timer.sto.push(
- setTimeout(function() {console.log("3s")}, 3000);
- );
- // 標(biāo)記 setIntervalID
- timer.siv.push(
- setInterval(function() {console.log("1s")}, 1000)
- );
在頁面需要 clearTimeout \ clearInterval 的時(shí)候,這樣調(diào)用:
- // 批量清除 setTimeout
- timer.sto.forEach(function(sto) {clearTimeout(sto)});
- // 批量清除 setInterval
- timer.siv.forEach(function(siv) {clearInterval(siv)});
暫停 & 恢復(fù)
近段時(shí)間,筆者發(fā)現(xiàn)很多業(yè)務(wù)都需要「暫?!购汀富謴?fù)」setTimeout & setInterval 的功能,而僅靠原生的四個(gè) APIs(setTimeout / setIntervale / clearTimeout / clearInterval)是不夠用的。于是,筆者對(duì) timer 進(jìn)行了擴(kuò)展,使它具備了「暫?!购汀富謴?fù)」的功能,如下:
- // 暫停所有的 setTimeout & setInterval
- timer.pause();
- // 恢復(fù)所有的 setTimeout & setInterval
- timer.resume();
擴(kuò)展后的 timer對(duì)象下面掛載6個(gè)基礎(chǔ)的 APIs。
- setTimeout
- setInterval
- clearTimeout
- clearInterval
- pause
- resume
使用 timer.set* & timer.clear* 來代替原生的 set* & clear*。筆者把擴(kuò)展后的 timer 托管在 GitHub 倉庫上,有興趣的同學(xué)可以移步:https://github.com/leeenx/timer
CreateJS 的啟發(fā)
在使用 CreateJS 開發(fā)一些項(xiàng)目的過程中,筆者發(fā)現(xiàn)通過設(shè)置 createjs.Ticker.paused = true / false,可以暫停/恢復(fù) createjs.Tween 上的動(dòng)畫。于是筆者借用 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。
其實(shí)就是在 createjs 對(duì)象下掛載四個(gè) APIs:
- setTimeout
- setInterval
- clearTimeout
- clearInterval
使用方法與原生的 setTimeout & setInterval 一樣,如下:
- let siv = createjs.setInterval(() => console.log("1s"), 1000);
- createjs.setTimeout(() => createjs.clearInterval(siv), 5000);
時(shí)間軸驅(qū)動(dòng)的 timer
createjs.timer 在 CreateJS 項(xiàng)目的開發(fā)給筆者帶來了極大的便利,但是它必須依賴 createjs.Tween 模塊。于是筆者就在思考能否創(chuàng)建一個(gè)跟第三方框架無關(guān)并且又可以在第三方框架上使用的 timer。
createjs.Ticker.paused 為什么能暫停 createjs.Tween 上的動(dòng)畫的?
createjs.Tween 中每一個(gè)動(dòng)畫都有一條自己的時(shí)間軸,這條時(shí)間軸是通過 createjs.Ticker 來驅(qū)動(dòng)的;當(dāng) createjs.Ticker 被暫停后,createjs.Tween 中的每個(gè)動(dòng)畫的時(shí)間軸也會(huì)失去動(dòng)力而暫停下來。
createjs.Ticker 的作用是提供一個(gè)刷新 canvas 畫面幀頻,通常是使用 requestAnimationFrame or setInterval 來實(shí)現(xiàn)的。如果 timer 內(nèi)部存在一條時(shí)間軸,這條時(shí)間軸由第三方驅(qū)動(dòng),那么 timer 就可以與第三方框架狀態(tài)同步了。
筆者是這樣設(shè)計(jì) timer 的結(jié)構(gòu):
- queue —— 存放 setTimeout or setInterval 的隊(duì)列;
- updateQueue —— 驅(qū)動(dòng) queue 的內(nèi)部 API;
- update —— 外部接口,用于對(duì)接第三方 Ticker。
實(shí)現(xiàn)的偽代碼如下:
- /*
- @queue 成員的結(jié)構(gòu)如下:
- {
- fn: fn, // 回調(diào)函數(shù)
- type: "timeout or interval", // 類型
- elapsed: 0, // 時(shí)間軸進(jìn)度
- delay: delay // 目標(biāo)時(shí)長(zhǎng)
- }
- */
- let queue = new Map();
- function updateQueue(delta) {
- queue.forEach((item, id) => {
- item.elapsed += delta;
- if(item.elapsed >= item.delay) {
- item.fn();
- // 從 queue 中刪除 setTimeout 成員,interval 成員繼續(xù)循環(huán)
- item.type === "timeout" ? delete(id) : (item.elapsed = 0);
- }
- });
- }
- // 對(duì)外接口
- this.update = function(delta) {
- updateQueue(delta);
- }
timer 的具體實(shí)現(xiàn)可以參考:https://github.com/leeenx/es6-utils#timer
timer 與 CreateJS 一起使用:
- // es6 代碼
- import timer from './modules/timer';
- // 統(tǒng)一 ticker
- createjs.Ticker.addEventListener("tick", function(e) {
- e.paused || timer.update(e.delta);
- });
timer 與 PIXI 一起使用:
- // es6 代碼
- import timer from './modules/timer';
- // 統(tǒng)一 ticker
- app.ticker.add("tick", function() {
- timer.update(app.ticker.elapsedMS);
- });
原文鏈接:https://aotu.io/notes/2017/09/25/manage-setTimeout-an-setInterval/
作者:leeenx
【本文是51CTO專欄作者“凹凸實(shí)驗(yàn)室”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過51CTO聯(lián)系原作者獲取授權(quán)】