本文共 4808 字,大约阅读时间需要 16 分钟。
在分析Deferred之前我觉得还是有必要把老套的设计模式给搬出来,便于理解源码!
观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一.
它定义了一种一对多的关系让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
使用观察者模式的好处:
观察者对象初始化变化请求,它不会立即更新,直到通过主题对象的Notify方法来获得一个变化的通知。主题的Notify方法并非总是被主题对象调用,它也能够被观察者对象调用,或者完全被其他不同类型的对象调用。
Deferred的定义:
Deferred提供的API
2 3 4 5 6 7 8 9 10 | var DeferredAPI = { deferred : deferred, all : all, Deferred : Deferred, DeferredList : DeferredList, wrapResult : wrapResult, wrapFailure : wrapFailure, Failure : Failure } |
我们通过简单的demo来解析程序的执行流程
2 3 4 5 6 7 8 9 10 11 12 | function asynchronous(delay,name) { var d = new deferred.Deferred() setTimeout( function () { d.resolve( '执行' +name) }, delay || 1000); return d }; var d1 = new asynchronous(1000, 'd1' ); d1.then( function (result){ alert(result) //结果是 执行d1 }) |
通过查看源码就能发现,其实Deferred.js的官方API不清晰,内部还有很多接口的实现没有说明
内部实现的处理器就2个模块,分别是:
new deferred.Deferred() deferred.deferred()
二着是等同的,最终的实现是Deferred类,每次实例化一次就是一个新是上下文
Deferred在构造之后,相对的实例就具有了以下方法:
来,订阅一个
Deferred.prototype.then = function (callback, errback) { this.callbacks.push({callback: callback, errback: errback}) if (this.called) _run(this) return this }
可以直接传入二个回调函数,分别对应都 done|fail 二个状态的回调, 跟 $.jquery还是有区别,可以直接传入三个回调函数,分别对应done|fail|progress三个状态的回调
用this.callbakcs 存储具体观察者感兴趣的内容
发布通知
Deferred.prototype.resolve = function(result) { _startRun(this, result) return this }
代码中间有很多逻辑判断,我们暂且先跳过,看看最终的执行方法
我们看看复杂点的构造
等待许多异步数据源
2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function asynchronous(delay,name) { var d = new deferred.Deferred() setTimeout( function () { d.resolve( '执行' +name) }, delay || 1000); return d }; var d1 = new asynchronous(2000, 'd1' ); var d2 = new asynchronous(3000, 'd2' ); deferred.all([d1, d2]).then( function (result){ console.log(result) //["执行d1", "执行d2"] }).thenCall(console.log(11111)); |
执行流程:
convert ['a', 'b', 'c'] to 'abc'
或者传入配置参数:
fireOnFirstResult: true 只要返回第一个d1处理
fireOnFirstError: true 只返回第一个错误的处理
2 3 4 | deferred.all([d1, d2],{fireOnFirstResult: true }).then( function (result){ console.log(result) //["执行d1"] }).thenCall(console.log(11111)); |
最后看2个API没有给出的接口
2 3 | dAll.failCall(console.error) dAll.then(join).thenCall(console.log) |
任意组合模式
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function asynchronous(delay,name) { var d = new deferred.Deferred() setTimeout( function () { d.resolve( '执行' +name) }, delay || 1000); return d }; var d1 = new asynchronous(2000, 'd1' ); var d = d1.then( function (result1) { var d2 = new asynchronous(200, 'd2' ); return d2.then( function (result2) { return result }) }).then( function (data) { console.log(data) return data }) |
执行流程:
总结: