微信号:FrontDev

介绍:分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯

管理页面的 setTimeout & setInterval

2017-10-05 20:00 前端大全

(点击上方公众号,可快速关注)


来源:凹凸实验室

aotu.io/notes/2017/09/25/manage-setTimeout-an-setInterval/

如有好文章投稿,请点击 → 这里了解详情



在管理 setTimeout & setInterval 这两个 APIs 时,笔者通常会在顶级(全局)作用域创建一个叫 timer 的对象,在它下面有两个数组成员 —— {sto, siv},用它们来分别存储需要管理的 setTimeoutID / setIntervalID。如下:


var timer = {

  sto: [],

  siv: []

};


在使用 setTimeout / setInterval 的时候,这样调用:


// 标记 setTimeoutID

timer.sto.push(

  setTimeout(function() {console.log("3s")}, 3000);

);

// 标记 setIntervalID

timer.siv.push(

  setInterval(function() {console.log("1s")}, 1000)  

);


在页面需要 clearTimeout \ clearInterval 的时候,这样调用:


// 批量清除 setTimeout

timer.sto.forEach(function(sto) {clearTimeout(sto)});

// 批量清除 setInterval

timer.siv.forEach(function(siv) {clearInterval(siv)});


暂停 & 恢复


近段时间,笔者发现很多业务都需要「暂停」和「恢复」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 一样,如下:


let siv = 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 // 目标时长

}

*/

let queue = new Map();

function updateQueue(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 = 0);

        }

    });

}

// 对外接口

this.update = function(delta) {

  updateQueue(delta);

}


timer 的具体实现可以参考:https://github.com/leeenx/es6-utils#timer


timer 与 CreateJS 一起使用:


// es6 代码

import timer from './modules/timer';

// 统一 ticker

createjs.Ticker.addEventListener("tick", function(e) {

  e.paused || timer.update(e.delta);

});


timer 与 PIXI 一起使用:


// es6 代码

import timer from './modules/timer';

// 统一 ticker

app.ticker.add("tick", function() {

  timer.update(app.ticker.elapsedMS);

});


附上 PIXI 的线上 DEMO,二维码如下:



总结


感谢阅读完本文章的读者。本文仅代表个人观点,希望能帮助到有相关问题的朋友,如果本文有不妥之处请不吝赐教。



看完本文有收获?请转发分享给更多人

关注「前端大全」,提升前端技能

 
前端大全 更多文章 如何提升页面渲染效率 Firefox 新版采用新引擎,速度是旧版的 2 倍,名字和 Logo 也变了 WordPress 宣布停止使用 React,网传百度也停用 React:15篇前端热文回看 趣图:用户看到的前端 vs 程序员看到的后端 JavaScript This 的六道坎
猜您喜欢 大浪淘沙,JSP终将死去 技术攻关:从零到精通 几行Python代码模拟轮盘抽奖游戏 Android Gradle 技巧之一: Build Variant 相关 设计模式(三)——JDK中的那些单例