JavaScript第二十四篇 高级定时器(下)
数组分块
所谓数组分块,就是当你发现某个循环占用了大量时间,同时对于上述两个问题,你的回答都是“否”,那么你就可以使用定时器分割这个循环。
思路是结合定时器进行递归调用定时器
基本示例如下:
setTimeout(function(){
//取出下一个条目并处理
var item = array.shift();
process(item);
//若还有条目,再设置另一个定时器
if(array.length > 0){
setTimeout(arguments.callee, 100);
}
}, 100);
封装成函数如下:
function chunk(array, process, context){
setTimeout(function(){
var item = array.shift();
process.call(context, item);
if (array.length > 0){
setTimeout(arguments.callee, 100);
}
}, 100);
}
chunk()方法接受三个参数:要处理的项目的数组,用于处理项目的函数,以及可选的运行该函数的环境。函数内部用了之前描述过的基本模式,通过call()调用的process()函数,这样可以设置一个合适的执行环境(如果必须)。定时器的时间间隔设置为了 100ms,使得 JavaScript进程有时间在处理项目的事件之间转入空闲。你可以根据你的需要更改这个间隔大小,不过100ms在大多数情况下效果不错。可以按如下所示使用该函数:
var data = [12,123,1234,453,436,23,23,5,4123,45,346,5634,2234,345,342];
function printValue(item){
var div = document.getElementById("myDiv");
div.innerHTML += item + "<br>";
}
chunk(data, printValue);
什么场景用?
数组分块 一般用于什么场景呢?一般用于耗时比较长的循环时,以防脚本长时间运行,导致浏览器崩溃
还有一种方法是吧数组以8为基数,0-8为一组,9-16为一组,以此类推,然后循环,这里里面的8个依次调用,只需要循环外面的大块,也能进行优化
函数节流
什么是函数节流?
某些代码不可以在没有间断的情况连续重复执行。第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。当第二次调用该函数时,它会清除前一次的定时器并设置另一个。如果前一个定时器已经执行过了,这个操作就没有任何意义。然而,如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器。目的是只有在执行函数的请求停止了一段时间之后才执行。
函数节流的基本模式如下:
var processor = {
timeoutId: null,
//实际进行处理的方法
performProcessing: function(){
//实际执行的代码
},
//初始处理调用的方法
process: function(){
clearTimeout(this.timeoutId);
var that = this;
this.timeoutId = setTimeout(function(){
that.performProcessing();
}, 100);
}
};
//尝试开始执行
processor.process();
简化以后:
function throttle(method, context) {
clearTimeout(method.tId);
method.tId= setTimeout(function(){
method.call(context);
}, 100);
}
函数节流的作用是在高频率得调用一个函数时,最终只会在停止触发后调用一次函数,能节省操作成本,和优化性能
自定义事件
事件,什么是事件?
事件是一种叫做观察者的设计模式,这是一种创建松散耦合代码的技术。对象可以发布事件,用来表示在该对象生命周期中某个有趣的时刻到了。然后其他对象可以观察该对象,等待这些有趣的时刻到来并通过运行代码来响应。
观察者模式:
观察者模式由两类对象组成:主体和观察者。主体负责发布事件,同时观察者通过订阅这些事件来观察该主体。该模式的一个关键概念是主体并不知道观察者的任何事情,也就是说它可以独自存在并正常运作即使观察者不存在。从另一方面来说,观察者知道主体并能注册事件的回调函数(事件处理程序)。涉及DOM上时,DOM元素便是主体,你的事件处理代码便是观察者。
事件是与 DOM 交互的最常见的方式,但它们也可以用于非 DOM 代码中——通过实现自定义事件。
自定义事件背后的概念是创建一个管理事件的对象,让其他对象监听那些事件。实现此功能的基本模式
可以如下定义:
function EventTarget(){
this.handlers = {};
}
EventTarget.prototype = {
constructor: EventTarget,
addHandler: function(type, handler){
if (typeof this.handlers[type] == "undefined"){
this.handlers[type] = [];
}
this.handlers[type].push(handler);
},
fire: function(event){
if (!event.target){
event.target = this;
}
if (this.handlers[event.type] instanceof Array){
var handlers = this.handlers[event.type];
for (var i=0, len=handlers.length; i < len; i++){
handlers[i](event);
}
}
},
removeHandler: function(type, handler){
if (this.handlers[type] instanceof Array){
var handlers = this.handlers[type];
for (var i=0, len=handlers.length; i < len; i++){
if (handlers[i] === handler){
break;
}
}
handlers.splice(i, 1);
}
}
};
EventTarget 类型有一个单独的属性handlers,用于储存事件处理程序。还有三个方法:addHandler() ,用于注册给定类型事件的事件处理程序;fire(),用于触发一个事件;removeHandler(),用于注销某个事件类型的事件处理程序。
addHandler()方法接受两个参数:事件类型和用于处理该事件的函数。当调用该方法时,会进行一次检查,看看handlers属性中是否已经存在一个针对该事件类型的数组;如果没有,则创建一个新的。然后使用 push()将该处理程序添加到数组的末尾。
如果要触发一个事件,要调用fire()函数。该方法接受一个单独的参数,是一个至少包含 type属性的对象。fire()方法先给event对象设置一个target属性,如果它尚未被指定的话。然后它就查找对应该事件类型的一组处理程序,调用各个函数,并给出 event 对象。因为这些都是自定义事件,所以event对象上还需要的额外信息由你自己决定。
removeHandler()方法是addHandler()的辅助,它们接受的参数一样:事件的类型和事件处理程序。这个方法搜索事件处理程序的数组找到要删除的处理程序的位置。如果找到了,则使用 break操作符退出for循环。然后使用splice()方法将该项目从数组中删除。
使用 EventTarget 类型的自定义事件可以如下使用:
function handleMessage(event){
alert("Message received: " + event.message);
}
//创建一个新对象
var target = new EventTarget();
//添加一个事件处理程序
target.addHandler("message", handleMessage);
//触发事件
target.fire({ type: "message", message: "Hello world!"});
//删除事件处理程序
target.removeHandler("message", handleMessage);
//再次,应没有处理程序
target.fire({ type: "message", message: "Hello world!"});
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。