驯服线程和定时器,管理页面的

管制页面的 set提姆eout & setInterval

2017/09/28 · JavaScript
· setInterval,
settimeout

原文出处:
坑坑洼洼实验室   

亚洲必赢官网 1在保管
set提姆(Tim)eout & setInterval 这五个 APIs
时,作者日常会在第顶级(全局)功用域创制一个叫 timer
的靶子,在它上边有五个数组成员 —— {sto, siv},用它们来分别存储须求管住的
set提姆eoutID / setIntervalID。如下:

JavaScript

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

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

在应用 set提姆eout / 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)
);

在页面需求 clear提姆eout \ clearInterval 的时候,那样调用:

JavaScript

// 批量清除 set提姆(Tim)eout timer.sto.forEach(function(sto)
{clear提姆eout(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 的职能,而仅靠原生的三个 APIs(set提姆eout / setIntervale /
clear提姆(Tim)eout / clearInterval)是不够用的。于是,小编对 timer
进行了伸张,使它拥有了「暂停」和「复苏」的效果,如下:

JavaScript

// 暂停所有的 set提姆eout & setInterval timer.pause(); // 復苏所有的
set提姆(Tim)eout & 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章 驯服线程和定时器

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

CreateJS 的启发

在采纳 CreateJS 开发一些档次的进度中,作者发现经过安装
createjs.Ticker.paused = true / false,可以暂停/恢复生机 createjs.Tween
上的卡通片。于是作者借用 createjs.Tween 模拟了 set提姆(Tim)eout & 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

运用方式与原生的 set提姆(Tim)eout & 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,很可能定时器就不设有了,必要协调落成自己的定时器版本。

代码如下: (function($) { (function($) {
$.preload = function(data, cfg) { return new Loader(data, cfg); }; var
maps = {}, on = $.event.add, un = $.event.remove, he…

时刻轴驱动的 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 中剔除 set提姆(Tim)eout
成员,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代码),定时器提出了一种跳出那种范围的章程,以一种不太直观的章程来进行代码。

总结

感谢阅读完本文章的读者。本文仅代表个人观点,希望能辅助到有相关题材的意中人,借使本文有不妥之处请不吝赐教。

1 赞 4 收藏
评论

亚洲必赢官网 3

8.1 定时器和线程是何许行事的

8.1.1 设置和扫除定时器

js提供了三种方法,用于创制定时器以及八个照应的破除方法(删除)。这个方式是window对象(全局上下文)上的方法。

id = set提姆(Tim)eout(fn,delay)
启动一个定时器,在一段时间(delay)之后执行传入的callback,并赶回该定时器的唯一标识

clear提姆eout(id)
即使定时器还未触及,传入定时器标识即可收回(清除)该定时器

id = setInterval(fn,delay)
启动一个定时器,在每隔一段时间之后都执行传入的callback,并赶回该定时器的唯一标识

clearInterval(id) 传入间隔定时器标识,即可收回该区间定时器

js定时器的延迟时间是不可以有限协助的,原因和js线程的面目有很大关系。

8.1.2 执行线程中的定时器执行

在Web
worker可用之前,浏览器中的所有js代码都是在单线程中施行的,是的,只有一个线程。

处理程序在履行时必须进行排队执行,并且一个处理程序并不能暂停其它一个处理程序的执行。

8.1.3 timeout与interval之间的区分

演示8.1 三种创制重复定时器的主意

set提姆(Tim)eout(function repeatMe(){
 //定义一个timeout定时器,每10阿秒都再一次调用自己

//code

setTimeout(repeatMe,10)

},10)

setInterval(function(){  //定义一个interval定时器,每10飞秒都触发一次

//code

},10)

在set提姆(Tim)eout()代码中,要在前一个callback回调执行落成并延迟10秒将来,才能重复实施set提姆(Tim)eout()。

而setInterval()则是每隔10阿秒就尝试举行callback回调,而不关切上一个callback是曾几何时实施的。

.js引擎是单线程执行,异步事件必需求排队等待才能实施

.如果不能即时实施定时器,该定时器会被推移到下一个可用的施行时间点上(可能更长,但不会比指定的延迟时间更少)。

.若是向来被推迟,到结尾,interval间隔定时器可能会无延迟执行,并且同一个interval处理程序的三个实例不可能而且展开排队。

.set提姆eout()和setInterval()在触及同期的定义上是一点一滴不一样的。

8.2 定时器延迟的最小化及其可信性

当代浏览器平时不可能兑现1飞秒粒度的可不断间隔,某些浏览器的完成可以分外相近。

当大家对setInterval()设置0微秒的延迟时,ie浏览器定时器的callback回调只会执行几回,和动用set提姆(Tim)eout效果同样。

浏览器不有限支撑大家指定的推移间隔,即便可以指定特定的延迟值,但其准确性却并不总是可以确保,尤其是在延迟值很小的时候。

8.3 处理昂贵的计量进度

js的单线程本质可能是js复杂应用程序开发中的最大“陷阱”。在js执行的时候,页面渲染的富有更新操作都要中断。

比方要保全界面有不错的响应能力,裁减运作时刻当先几百阿秒的复杂操作,将其决定在可管理意况是卓殊要求的。

即使一段脚本的运作时刻当先5秒,有些浏览器将弹出一个对话框警告用户该脚本“不能响应”。小米上的浏览器,将默许终止运行时刻超越5分钟的脚本。

用作定时器,它在一段时间之后,可以使得暂停一段js代码的推行,定时器还足以将代码的相继部分,分解成不会让浏览器挂掉的零碎。

考虑到那或多或少,我们能够将强循环和操作转化为非阻塞操作。

以身作则8.2 一个长日子运作的义务

var tbody = document.getElementsByTagName(‘tbody’)[0];

for(var i=0; i<20000; i++){

var tr = document.createElement(‘tr’);

for(var t=0; t<6; t++){

var td = document.createElement(‘td’);

td.appendChild(document.createTextNode(i+’,’+t));

tr.appendChild(td);

}

tbody.appendChild(tr)

}

上例创立了240000个DOM节点,并应用多量的单元格来填充一个表格。那是相当高昂的操作,显著会增多浏览器的实施时间,从而阻碍正常的用户交互操作。

我们可以引入定时器,在代码执行的时候定期暂停休息

以身作则8.3 利用定时器分解长日子运作的职责

var tbody = document.getElementsByTagName(‘tbody’)[0];

var rowCount = 20000;

var divideInto = 4;

var chunkSize = rowCount/divideInto;

var iteration = 0;

setTimeout(function generateRows(){

var base = (chunkSize)*iteration;

for(var i=0; i

var tr = document.createElement(‘tr’);

for(var t=0; t<6; t++){

var td = document.createElement(‘td’);

td.appendChild(document.createTextNode((i+base)+’,’+t+’,’+iteration));

tr.appendChild(td)

}

tbody.appendChild(tr);

}

iteration++;

if(iteration

setTimeout(generateRows,0)

}

},0);

上例将操作分成四步小操作,每个操作创造自己的DOM节点。那么些较小的操作,则不太可能让浏览器挂掉。

8.4 中心定时器控制

行使定时器可能出现的问题是对大量定时器的管理。

与此同时创设大气的定时器,将会在浏览器中追加垃圾回收职分的可能性。垃圾回收就是浏览器遍历其分配过的内存,并打算删除没有其余利用的未利用对象的历程。定时器是一个非正规的问题,因为常常它们是在js单线程引擎之外的流程中举办保管。有些浏览器可以很好地拍卖那种场所,有些浏览器的废品回收周期则很长。一个动画片在某个浏览器中很赏心悦目、很流畅,但在其余一个浏览器中却很卡顿。

在七个定时器中选取要旨定时器控制,可以带来很大的威力和灵活性。

.每个页面在同一时间只必要周转一个定时器。

.可以按照要求暂停和回复定时器。

.删除回调函数的经过变得很粗略。

以身作则8.4 管理多少个处理程序的中心定时器控制

test suite

#box{position:absolute;width:60px;height:40px;border:1px solid #060; text-align:center;}

Hello!

var timers={

timerID:0,

timers:[],

add:function(fn){

this.timers.push(fn);

},

start:function runNext(){

if(this.timerID) return;

(function(){

if(timers.timers.length > 0){

for(var i=0; i

if(timers.timers[i]() === false){

timers.timers.splice(i,1);

i–

}

}

timers.timerID = setTimeout(runNext,0)

}

})()

},

stop:function(){

clearTimeout(this.timerID);

this.timerID=0;

}

}

var box = document.getElementById(‘box’),x=0,y=20;

timers.add(function(){

box.style.left = x + ‘px’;

if(++x>50) return false;

})

timers.add(function(){

box.style.top = y+’px’;

y+=2;

if(y>120) return false;

})

timers.start();

一起头,所有的回调函数都存储于一个名为timers的数组中,还包括当前定时器的一个ID,这一个变量是定时器唯一需求维护的内容。

add()方法接受一个callback回调,并简短将其添加到timers数组中。

start()方法首先肯定没有定时器在运作(通过检查timerID是或不是有值),假设认可没有定时器在执行,马上施行一个即时函数来拉开要旨定时器。

在马上函数内,假诺注册了处理程序,就遍历执行各种处理程序。假诺有处理程序再次来到false,大家就从数组上校其删除,最终举行下两回调度。

以那种艺术社团定时器,可以有限帮忙回调函数总是依据添加的逐一举行实践。而常见的定时器寻常不会确保那种顺序,有可能前边的一个处理程序在前头就实施了。

那种方法的定时器协会,对于大型应用程序或其他格局的js动画来说都是必不可缺的。

8.5 异步测试

以身作则:简单的异步测试套件

(function(){

var queue = [],paused=false;

this.test = function(fn){

queue.push(fn);

runTest();

}

this.pause = function(){

paused = true;

}

this.resume = function(){

paused = false;

setTimeout(runTest,1)

}

function runTest(){

if(!paused && queue.length){

queue.shift();

if(!paused) resume();

}

}

})()

示范中,传递给test()方法的每个函数,最多只含有一个异步测试。它们的异步性由pause()和resume()的采纳所定义,这七个法子分别在异步事件以前或之后展开调用。那段代码是一种保障让包罗异步行为的函数,以一定的逐条举办实践的点子。

该队列唯一的目标是在守候执行的时候,出列一个函数并举行实践。否则,就全盘终止运行一个时日距离。

那段代码,强制测试套件以纯粹异步方式进行实施,但同时又有限扶助了测试执行的相继。

网站地图xml地图