姊妹篇 移动web app开发必备 - 异步队列 Deferredhtml
在分析Deferred以前我以为仍是有必要把老套的设计模式给搬出来,便于理解源码!jquery
观察者模式( 又叫发布者-订阅者模式 )应该是最经常使用的模式之一.web
它定义了一种一对多的关系让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知全部的观察者对象,使得它们可以自动更新本身。编程
使用观察者模式的好处:设计模式
观察者对象初始化变化请求,它不会当即更新,直到经过主题对象的Notify方法来得到一个变化的通知。主题的Notify方法并不是老是被主题对象调用,它也可以被观察者对象调用,或者彻底被其余不一样类型的对象调用。数组
Deferred的定义:promise
Deferred提供的APIapp
var DeferredAPI = { deferred : deferred, all : all, Deferred : Deferred, DeferredList : DeferredList, wrapResult : wrapResult, wrapFailure : wrapFailure, Failure : Failure }
咱们经过简单的demo来解析程序的执行流程异步
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不清晰,内部还有不少接口的实现没有说明async
内部实现的处理器就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 }
代码中间有不少逻辑判断,咱们暂且先跳过,看看最终的执行方法
1 function _run(d) { 2 if (d.running) return 3 var link, status, fn 4 if (d.pauseCount > 0) return 5 6 while (d.callbacks.length > 0) { 7 link = d.callbacks.shift() 8 status = (d.result instanceof Failure) ? 'errback' : 'callback' 9 fn = link[status] 10 if (typeof fn !== 'function') continue 11 try { 12 d.running = true 13 d.result = fn(d.result) 14 d.running = false 15 if (d.result instanceof Deferred) { 16 d.pause() 17 _nest(d) 18 return 19 } 20 } catch (e) { 21 if (Deferred.consumeThrownExceptions) { 22 d.running = false 23 var f = new Failure(e) 24 f.source = f.source || status 25 d.result = f 26 if (d.verbose) { 27 console.warn('uncaught error in deferred ' + status + ': ' + e.message) 28 console.warn('Stack: ' + e.stack) 29 } 30 } else { 31 throw e 32 } 33 } 34 } 35 }
咱们看看复杂点的构造
等待许多异步数据源
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 只返回第一个错误的处理
deferred.all([d1, d2],{fireOnFirstResult: true}).then(function(result){ console.log(result) //["执行d1"] }).thenCall(console.log(11111));
最后看2个API没有给出的接口
dAll.failCall(console.error) dAll.then(join).thenCall(console.log)
任意组合模式
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 })
执行流程:
总结:
考虑这章拉的太长了,你们看的会有点小闷,因此下一节就开始队列的源码分析了