用它们来分别存储需要管理的,如果我们在非浏

管理页面包车型客车 set提姆eout & setInterval

2017/09/28 · JavaScript · setInterval, settimeout

原来的小讲出处: 坑坑洼洼实验室   

图片 1在保管 setTimeout & setInterval 那五个 APIs 时,作者日常会在超级(全局卡塔尔国功效域创造一个叫 timer 的对象,在它下边有多个数组成员 —— {sto, siv},用它们来分别存款和储蓄需求管住的 setTimeoutID / setIntervalID。如下:

JavaScript

var timer = { sto: [], siv: [] };

1
2
3
4
var timer = {
sto: [],
siv: []
};

在利用 setTimeout / setInterval 的时候,那样调用:

JavaScript

// 标记 setTimeoutID timer.sto.push( setTimeout(function() {console.log("3s")}, 3000); ); // 标记 setIntervalID timer.siv.push( setInterval(function() {console.log("1s")}, 1000) );

1
2
3
4
5
6
7
8
// 标记 setTimeoutID
timer.sto.push(
setTimeout(function() {console.log("3s")}, 3000);
);
// 标记 setIntervalID
timer.siv.push(
setInterval(function() {console.log("1s")}, 1000)
);

在页面要求 clearTimeout clearInterval 的时候,那样调用:

JavaScript

// 批量肃清 setTimeout timer.sto.forEach(function(sto) {clearTimeout(sto)}); // 批量消除 setInterval timer.siv.forEach(function(siv) {clearInterval(siv)});

1
2
3
4
// 批量清除 setTimeout
timer.sto.forEach(function(sto) {clearTimeout(sto)});
// 批量清除 setInterval
timer.siv.forEach(function(siv) {clearInterval(siv)});

复制代码 代码如下:

9.26-9.30

定时器 setTimeout、setInterval

暂停 & 恢复

近段时日,小编开采众多工作都急需「暂停」和「苏醒」setTimeout & setInterval 的意义,而仅靠原生的三个 APIs(setTimeout / setIntervale / clearTimeout / clearInterval卡塔 尔(英语:State of Qatar)是非常不够用的。于是,小编对 timer 进行了扩大,使它富有了「暂停」和「复苏」的功用,如下:

JavaScript

// 暂停全数的 setTimeout & setInterval timer.pause(); // 恢复全部的 setTimeout & setInterval timer.resume();

1
2
3
4
// 暂停所有的 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 仓库上,有意思味的同窗能够移动:

(function($) {
(function($) {
$.preload = function(data, cfg) {
return new Loader(data, cfg);
};
var maps = {}, on = $.event.add, un = $.event.remove, head = document.getElementsByTagName('head')[0], body =
document.body, bs = $.browser, ie = bs.msie, webkit = bs.webkit, gecko = bs.mozilla, space = 1000, ajax =
$.ajax,
loaders = $.preload.loaders = {
'js' : function(url, callback, timeout, defer) {
var s, timer;
if (defer) {
if (ie) {
return loaders.img(url, callback, timeout);
} else {
s = document.createElement('object');
s.data = url;
s.width = s.height = 0;
}
} else {
s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.setAttribute('src', url);
}
function f() {
if (timer)
clearTimeout(timer);
s.onreadystatechange = s.onload = s.onerror = null;
callback(url, false);
}
if (ie) {
s.onreadystatechange = function() {
if (this.readyState === 'loaded' || this.readyState === 'complete') {
if (timer)
clearTimeout(timer);
s.onreadystatechange = null;
callback(url, true);
}
};
} else {
s.onload = function() {
if (timer)
clearTimeout(timer);
s.onload = s.onerror = null;
callback(url, true);
};
s.onerror = f;
}
timer = setTimeout(f, timeout);
body.appendChild(s);
},
'css' : function(url, callback, timeout, defer) {
if (defer) {
return loaders.js(url, callback, timeout, defer);
}
var s = document.createElement('link'), timer;
s.setAttribute('rel', 'stylesheet');
s.setAttribute('type', 'text/css');
s.setAttribute('href', url);
function f() {
if (timer)
clearTimeout(timer);
s.onreadystatechange = s.onload = s.onerror = null;
callback(url, false);
}
if (ie) {
s.onreadystatechange = function() {
if (this.readyState === 'loaded' || this.readyState === 'complete') {
if (timer)
clearTimeout(timer);
s.onreadystatechange = null;
callback(url, true);
}
};
timer = setTimeout(f, timeout);
} else if (webkit || gecko) {
timer = new Date();
function f() {
if (('sheet' in s) && ('cssRules' in s.sheet)) {
try {
callback(url, !!s.sheet.cssRules[0]);
} catch (e) {
setTimeout(f, space);
}
} else if (new Date() - timer > timeout) {
callback(url, false);
} else {
setTimeout(f, space);
}
}
setTimeout(f, space * 2);
} else {
s.onload = function() {
if (timer)
clearTimeout(timer);
s.onload = s.onerror = null;
callback(url, true);
};
s.onerror = f;
timer = setTimeout(f, timeout);
}
head.appendChild(s);
},
'img' : function(url, callback, timeout) {
var s = new Image(), timer;
function f() {
if (timer)
clearTimeout(timer);
s.onload = s.onerror = null;
callback(url, false);
}
s.onload = function() {
if (timer)
clearTimeout(timer);
s.onload = s.onerror = null;
callback(url, true);
};
s.onerror = f;
timer = setTimeout(f, timeout);
s.src = url;
},
'ajax' : function(url, callback, cfg) {
cfg = cfg || {};
cfg.url = url;
cfg.success = function(data) {
callback(url, true, data);
};
cfg.error = function() {
callback(url, false);
};
ajax(cfg);
}
};
function Loader(data, cfg) {
var self = this, cur = -1, items = [], pendings = [], done, i = 0, l = data.length, j, m, s, t, c, d, tt, item, doing =
0, load;
cfg = cfg || {};
for (; i < l; ++i) {
item = data[i];
if (typeof item === 'string') {
s = item.substr(item.lastIndexOf('.') + 1);
items.push(maps[item] = {
type : loaders[s] ? s : 'img',
url : item
});
} else if (item.urls) {
for (j = 0, s = item.type, t = item.require, c = item.callback, d = item.defer, tt = item.timeout, item =
item.urls, m = item.length; j < m; ++j) {
s = s || item[j].substr(item[j].lastIndexOf('.') + 1);
items.push(maps[item[j]] = {
type : loaders[s] ? s : 'img',
url : item[j],
require : t,
callback : c,
defer : d,
timeout : tt
});
}
} else {
if (!item.type) {
s = item.url.substr(item.url.lastIndexOf('.') + 1);
item.type = loaders[s] ? s : 'img';
}
items.push(maps[item.url] = item);
}
}
this.success = this.fail = this.progress = 0;
if (cfg.onFinish)
this.onFinish = cfg.onFinish;
timeout = cfg.timeout || 2000;
function callback(url, flag, data) {
if (flag) {
++self.success;
} else {
++self.fail;
}
self.progress = (self.success + self.fail) / items.length;
console.info(url);
console.warn(flag);
item = maps[url];
item.success = flag;
if (self.progress === 1) {
self.stop();
}
if (item.parent && !item.defer && !cfg.defer) {
$(item.parent)[0].innerHTML = data || '';
}
if (item.callback) {
item.callback(data);
}
item.done = true;
--doing;
}
function runnable(item, pend) {
var it;
if (typeof item.require === 'string') {
if (item.done)
return false;
if (!item.require)
return true;
it = maps[item.require];
if (!it || it.done) {
if (pend)
pendings.shift();
if (it && it.success) {
return true;
} else {
callback(item.url, false);
}
} else if (!pend) {
pendings.push(item);
}
} else {
for (it = item.length; it--;) {
if (!runnable(item[it], pend))
return false;
}
return true;
}
}
function run() {
var item = pendings[0];
if (!item || !runnable(item, true)) {
while (item = items[++cur]) {
if (runnable(item)) {
break;
}
}
}
if (item) {
var fn = loaders[item.type || 'img'];
if (fn) {
++doing;
if (item.type === 'ajax') {
if (item.cfg && !item.cfg.timeout)
item.cfg.timeout = timeout;
fn(item.url, callback, item.cfg);
} else {
fn(item.url, callback, item.timeout || timeout, item.defer === undefined ? cfg.defer
: item.defer);
}
};
if (load) {
run();
} else {
self.timer = setTimeout(run, space);
}
} else if (pendings.length) {
self.timer = setTimeout(run, space);
}
}
this.start = function(delay) {
if (!done)
this.timer = setTimeout(run, delay > space ? delay : space);
};
this.stop = function() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
done = true;
if (this.onFinish) {
if (!doing)
this.onFinish();
else {
s = setInterval(function() {
if (!doing) {
clearInterval(s);
self.onFinish();
}
}, space);
}
}
}
};
this.pause = function() {
clearTimeout(this.timer);
};
this.resume = function() {
this.timer = setTimeout(run, space);
};
this.load = function() {
clearTimeout(this.timer);
load = true;
run();
};
}
})(jQuery);
/**
* @example
* var loader = $.preload([
// 字符串,选择暗许配置
'1.jpg', '1.js',
// 对象,自定义配置,如type, require, timeout, defer, callback
{
type : 'img',
url : '',
timeout : 10
}, {
url : '3.js',
callback : fn,
defer : true,
require : '1.js'
},
// 对象,可用urls钦命大器晚成组同样配置
{
type : 'css',
urls : ['4.css', '5.css']
}], {
// 加载结束后调用
onFinish : fn,
// 加载超时
timeout : 50
});
// 以前预加载
loader.start();
loader.stop();
// 暂停预加载
loader.pause();
loader.resume();
// 实时加载
loader.load();
*/

第8章 驯服线程和机械漏刻

沙漏的应用格局

  • setTimeout(fn,1000) : 1s后实践fn函数(仅贰回,不会循环触发卡塔 尔(英语:State of Qatar);
  • setInterval(fn,1000) : 1s实行二遍fn函数(循环触发卡塔尔;
    互相用法相同,只是前者只进行三遍,前者会Infiniti循环。

CreateJS 的启发

在应用 CreateJS 开垦一些类其余过程中,作者发掘经过安装 createjs.Ticker.paused = true / false,能够暂停/苏醒 createjs.Tween 上的动漫。于是小编借用 createjs.Tween 模拟了 setTimeout & setInterval 的机能,如下:

JavaScript

// 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; }

1
2
3
4
5
6
7
8
// 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。
实际上正是在 createjs 对象下挂载多少个 APIs:

  • setTimeout
  • setInterval
  • clearTimeout
  • clearInterval

应用办法与原生的 setTimeout & setInterval 同样,如下:

JavaScript

let siv = createjs.setInterval(() => console.log("1s"), 1000); createjs.setTimeout(() => createjs.clearInterval(siv), 5000);

1
2
let siv = createjs.setInterval(() => console.log("1s"), 1000);
createjs.setTimeout(() => createjs.clearInterval(siv), 5000);

计时器可以在js中央银行使,但它不是js的意气风发项成效,如若我们在非浏览器情形中选择js,非常大概计时器就官样文章了,须要自个儿达成协和的沙漏版本。

传递参数

诚如意况下,大家不可能一直在电磁打点计时器中央司法机关接传参,不然函数就能自施行,不在是三个函数。

  • setInterval(“fn(a)”,1000):就要传参的函数用 “ ” 包裹,电磁打点计时器会自动识别字符串并试行里面的函数。
    注意:有功效域难点,假使加引号,fn函数必需定义在window.onload之外,不然setInterval(“fn(a)”,1000); fn是not defined。
  • setTimeout(function(){ fn(a);fn1(b); },1000):就要函数用佚名函数function(卡塔尔国{ }包裹,这种方法能够并且进行多个函数。
  • setTimeout(eval(“fn()”),1000):eval方法会把里面包车型地铁字符串产生可履行的代码。

时刻轴驱动的 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。

完成的伪代码如下:

JavaScript

/* @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); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
@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 的实际贯彻能够参照:

timer 与 CreateJS 一同使用:

JavaScript

// es6 代码 import timer from './modules/timer'; // 统一 ticker createjs.Ticker.addEventListener("tick", function(e) { e.paused || timer.update(e.delta); });

1
2
3
4
5
6
// es6 代码
import timer from './modules/timer';
// 统一 ticker
createjs.Ticker.addEventListener("tick", function(e) {
  e.paused || timer.update(e.delta);
});

timer 与 PIXI 一齐使用:

JavaScript

// es6 代码 import timer from './modules/timer'; // 统一 ticker app.ticker.add("tick", function() { timer.update(app.ticker.elapsedMS); });

1
2
3
4
5
6
// es6 代码
import timer from './modules/timer';
// 统一 ticker
app.ticker.add("tick", function() {
  timer.update(app.ticker.elapsedMS);
});

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

图片 2

放大计时器提供了风流洒脱种让生龙活虎段代码在必然阿秒之后,再异步施行的力量。由于js是单线程的性情(同一时候只可以进行大器晚成处js代码卡塔 尔(英语:State of Qatar),电火花计时器提出了生机勃勃种跳出这种范围的点子,以大器晚成种不太直观的点子来进行代码。

清除沙漏

平时页面上的电磁打点计时器实施完记得都要破除

  • clearTimeout(timer)
  • clearInterval(timer)

在扼杀电磁打点计时器前,我们供给先给放大计时器三个名字手艺肃清;如作者辈要先 var timer = setTimeout(fn(),1000卡塔 尔(阿拉伯语:قطر‎;然后大家工夫运用 clearTimeout(timer卡塔尔国;消逝。

总结

感激阅读完本小说的读者。本文仅代表个人观点,希望能支援到有相关主题材料的相恋的人,假如本文有不妥之处请多多点拨。

1 赞 4 收藏 评论

图片 3

8.1 计时器和线程是什么行事的

HTML5下 的requestAnimationFrame函数

requestAnimationFrame函数是针对性动漫效果的API,在浏览器中优化并行的动漫动作。它的效用与定时器相通,可是它的间隔时间为浏览器本人的间隔时间。宽容主流浏览器,可是不宽容IE8以下。

  • requestAnimationFrame(fn卡塔 尔(阿拉伯语:قطر‎: 一定间距之后实施fn函数
  • cancelAnimationFrame(timer) : 撤消动漫帧诉求,也要提前给名字

8.1.1 设置和撤消机械漏刻

js提供了二种格局,用于创立电磁打点计时器以致七个照应的消亡方法(删除卡塔 尔(阿拉伯语:قطر‎。那个措施是window对象(全局上下文卡塔 尔(英语:State of Qatar)上的不二法门。

id = setTimeout(fn,delay) 运维一个电火花计时器,在黄金时代段时间(delay)之后试行传入的callback,并回到该停车计时器的天下第一标志

clearTimeout(id) 要是沙漏还未有触及,传入坚持计时器标志就可以收回(废除卡塔 尔(英语:State of Qatar)该电磁打点计时器

id = setInterval(fn,delay) 运转叁个沙漏,在每间距生机勃勃段时间之后都实行传入的callback,并重返该机械漏刻的唯大器晚成标志

clearInterval(id) 传入间距电火花计时器标志,就可以收回该间隔停车计时器

js反应计时器的延迟时间是不能够承保的,原因和js线程的真面目有十分大关系。

8.1.2 奉行线程中的电火花计时器实行

在Web worker可用在此之前,浏览器中的全部js代码都是在单线程中举行的,是的,独有一个线程。

管理程序在实行时必需进行排队实行,何况一个处理程序并无法暂停此外一个管理程序的实践。

8.1.3 timeout与interval之间的区分

亲自去做8.1 二种创设重复电磁打点计时器的章程

setTimeout(function repeatMe(){  //定义贰个timeout计时器,每10皮秒都再也调用本身

//code

setTimeout(repeatMe,10)

},10)

setInterval(function(){  //定义多少个interval机械漏刻,每10飞秒都触发一回

//code

},10)

在setTimeout()代码中,要在前三个callback回调施行完成并延迟10秒以后,工夫再一次实行setTimeout()。

而setInterval()则是每间距10皮秒就尝试推行callback回调,而不尊敬上三个callback是曾几何时实践的。

.js引擎是单线程施行,异步事件必须求排队等候本领施行

.假使不大概即时举行沙漏,该沙漏会被延缓到下多少个可用的实践时间点上(或者更加长,但不会比内定的延迟时间更加少卡塔 尔(英语:State of Qatar)。

.假如一向被推迟,到最后,interval间距沙漏恐怕会无延迟实践,况兼同一个interval管理程序的多个实例不可能何况扩充排队。

.setTimeout()和setInterval()在接触同一时候的概念上是完全两样的。

8.2 反应计时器延迟的最小化及其可信性

现代浏览器经常无法兑现1飞秒粒度的可不断间距,有些浏览器的贯彻能够丰硕近似。

当大家对setInterval()设置0纳秒的推迟时,ie浏览器电磁打点计时器的callback回调只会举行三回,和行使setTimeout效果等同。

浏览器不保证大家钦命的延时期隔,即使能够钦点特定的延迟值,但其准确性却并不一而再连续能够保险,极其是在延迟值超级小的时候。

8.3 管理昂贵的测算进度

js的单线程本质大概是js复杂应用程序开辟中的最大“陷阱”。在js实施的时候,页面渲染的有着更新操作都要行车制动器踏板。

豆蔻梢头经要保全分界面有精彩的响应工夫,减弱运作时刻超过几百飞秒的犬牙相错操作,将其决定在可拘禁景况是十二分供给的。

假设风度翩翩段脚本的运作时刻超过5秒,有个别浏览器将弹出多少个对话框警报客商该脚本“不能够响应”。One plus上的浏览器,将暗中认可终止运营时刻超越5分钟的台本。

用作计时器,它在后生可畏段时间之后,能够使得暂停大器晚成段js代码的施行,反应计时器还足以将代码的相继部分,分解成不会让浏览器挂掉的零碎。

本文由必威发布于必威-前端,转载请注明出处:用它们来分别存储需要管理的,如果我们在非浏

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。