您的位置:首页 > 移动开发

移动web app开发必备 - Deferred 源码分析

2013-07-04 09:32 169 查看
姊妹篇 移动web app开发必备 - 异步队列 Deferred

在分析Deferred之前我觉得还是有必要把老套的设计模式给搬出来,便于理解源码!

观察者模式

观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一.

它定义了一种一对多的关系让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。

使用观察者模式的好处:

支持简单的广播通信,自动通知所有已经订阅过的对象。

页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。

目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。

在这种模式中,有两类对象,分别是“观察者-Observer”和“目标对象-Subject”。

目标对象中保存着一份观察者的列表,当目标对象的状态发生改变的时候就主动向观察者发出通知(调用观察者提供的方法),从而建立一种发布/订阅的关系。

这一种发布/订阅的关系常用于实现事件、消息的处理系统。

观察者模式类图

function _run(d) {
if (d.running) return
var link, status, fn
if (d.pauseCount > 0) return

while (d.callbacks.length > 0) {
link = d.callbacks.shift()
status = (d.result instanceof Failure) ? 'errback' : 'callback'
fn = link[status]
if (typeof fn !== 'function') continue
try {
d.running = true
d.result = fn(d.result)
d.running = false
if (d.result instanceof Deferred) {
d.pause()
_nest(d)
return
}
} catch (e) {
if (Deferred.consumeThrownExceptions) {
d.running = false
var f = new Failure(e)
f.source = f.source || status
d.result = f
if (d.verbose) {
console.warn('uncaught error in deferred ' + status + ': ' + e.message)
console.warn('Stack: ' + e.stack)
}
} else {
throw e
}
}
}
}


View Code

运行流程

其中d就是传入的异步对象了

d.callbacks就是订阅收集的具体观察者感兴趣的内容,也就是callback or errback

匹配出正确的回调方法,执行

d.result = fn(d.result) 传入回调函数需要的参数

单一的流程就执行完毕了

我们看看复杂点的构造

案例分析二

等待许多异步数据源

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));

执行流程:

等待在一个列表的所有值的递延的对象,或者开始一群延迟操作和运行回调链当第一个成功还是失败了

等待d1, d2都加载完毕后接受到所有的values后,deferred.all运行作用域链,当然也一样可以提供成功或者失败

返回的result将会是数组格式的
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
})

执行流程:

一个回调函数的返回值被传递到下一个回调。

当一个回调返回一个延迟对象,原来的延迟将透明地等待其他接收它的值,然后运行它自己的回调链使用该值。我们把这种叫做嵌套。

总结:

现在我们可以用deferred对象做很多事了,返回它,将它传递给另一个函数,等。

随后的回调注册在deferred将收到返回的值从最内层的回调:result1+ result2。

用起来是不是很爽!

考虑这章拉的太长了,大家看的会有点小闷,所以下一节就开始队列的源码分析了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: