1. 前言
最近在看司徒正美的《javascript框架设计》,看到异步编程的那一章介绍了jsdeferred这个库,觉得很有意思,花了几天的时间研究了一下代码,在此做一下分享。
异步编程是编写js的一个很重要的理念,特别是在处理复杂应用的时候,异步编程的技巧就至关重要。那么下面就来看看这个被称为里程碑式的异步编程库吧。
2. api源码解析
2.1 构造函数
这里使用了安全的构造函数,避免了在没有使用new调用构造函数时出错的问题,提供了两个形式俩获取deferred对象实例。
function deferred() {
return (this instanceof deferred) ? this.init() : new deferred();
}
// 方式1
var o1 = new deferred();
// 方式2
var o2 = deferred();
2.2 deferred.define()
这个方法可以包装一个对象,指定对象的方法,或者将deferred对象的方法直接暴露在全局作用域下,这样就可以直接使用。
deferred.methods = [parallel, wait, next, call, loop, repeat, chain];
/*
@param obj 赋予该对象deferred的属性方法
@param list 指定属性方法
*/
deferred.define = function(obj, list){
if(!list)list = deferred.methods;
// 获取全局作用域的技巧,利用立即执行函数的作用域为全局作用域的技巧
if(!obj) obj = (function getglobal(){return this})();
// 将属性都挂载到obj上
for(var i = 0; i bar.html data
});
3. parallel([fn1, fn2, fn3]).next(function (v) {
v[0] // fn1执行的结果
v[1] // fn2执行的结果
v[3] // fn3执行返回的结果
});
*/
var isarray = false;
// 第一种形式
if (arguments.length > 1) {
dl = array.prototype.slice.call(arguments);
isarray = true;
// 其余两种形式,数组,类数组
} else if (array.isarray && array.isarray(dl)
|| typeof dl.length == number) {
isarray = true;
}
var ret = new deferred(), // 用于归并结果的deferred对象的实例
value = {}, // 收集函数执行的结果
num = 0 ; // 计数器,当为0时说明所有任务都执行完毕
// 开始遍历,这里使用for-in其实效率不高
for (var i in dl) {
// 预防遍历了所有属性,例如tostring之类的
if (dl.hasownproperty(i)) {
// 利用闭包保存变量状态
(function (d, i){
// 使用deferred.next()开始一个异步任务,并且执行完成之后,收集结果
if (typeof d == function) dl[i] = d = deferred.next(d);
d.next(function (v) {
values[i] = v;
if( --num task1返回的结果
ret[1]; // => task2返回的结果
});
为什么可以这样?我们来图解一下,加深一下理解。
我们使用了_fire中的if判断,建立了新的调用链,获得去统计计数函数(即parallel中--num)的控制权,从而使得在parallel执行异步的方法。