移动web app开发,异步代码是时常的事,比如有常见的异步操作:
后面几个是CSS3 HML5加入的新API.这些接口都是会产生异步的操作
比如本人的一个phonegap项目,操作HTML5本地数据库(HTML5 Web Database)就是一个异步的过程,如果同时执行多个查询,势必同步代码要等待数据查询结束后调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
/**
* 初始化操作
* @return
*/
proto.initProcess =
function
(){
var
self =
this
,
prev =
null
,
curr =
null
,
next =
null
;
debug.group(
"start of init process"
);
var
idx = self.chapterIndex;
debug.info(
"PageBase: 执行初始化之前的操作!"
);
self.initProcessBefore();
if
(idx == 0){
debug.info(
"PageBase: 初始化入口点从第一章开始进入"
);
debug.info(
"PageBase: 解析器解析第一章数据!"
);
curr = self.process(self.chapters[idx]);
curr.then(
function
(pages){
debug.info(self.format(
"PageBase: 第一章数据解析完成,解析页面数为{0}"
, pages.length));
self.cPages = pages;
if
(self.isChangeFont){
self.idx = Math.ceil((pages.length - 1) * self.idx);
}
self.cPages.idx = idx;
/////////////////////////////////////////////////
//
// 2013.1.10修改
// 如果只有一个章节的情况下
//
if
(1 === self.chapters.length){
deferred.all([curr]).then(self.steup.bind(self));
}
else
{
debug.info(
"PageBase:解析器解析后一章数据!"
);
next = self.loadNextData(idx + 1);
next.then(
function
(args){
debug.info(self.format(
"PageBase: 后一章数据解析完成,解析页面数为{0}"
, args.pages.length));
self.nPages = args.pages;
self.nPages.idx = idx + args.index;
debug.info(self.format(
"PageBase: 初始化数据解析完成, 当章索引{0} 当章页数{1} 下章索引{2} 下章页数{3}"
, self.cPages.idx , self.cPages.length , self.nPages.idx , self.nPages.length));
debug.info(
"PageBase: 初始化数据解析完成,即将生成结构操作!"
);
});
deferred.all([curr , next]).then(self.steup.bind(self));
}
});
}
else
if
(idx == self.chapters.length -1){
debug.info(
"PageBase: 初始化入口点从最后一章开始进入"
);
debug.info(
"PageBase:解析器解析最后一章数据!"
);
prev = self.loadPrevData(idx - 1);
prev.then(
function
(args){
self.pPages = args.pages;
self.pPages.idx = args.index + 1;
debug.info(self.format(
"PageBase: 最后一章的前一章数据解析完成,解析页面数为{0}"
, args.pages.length));
curr = self.process(self.chapters[idx]);
curr.then(
function
(pages , data){
if
(self.isChangeFont){
self.idx = Math.ceil((pages.length - 1) * self.idx);
}
self.cPages = pages ;
self.cPages.idx = idx;
debug.info(self.format(
"PageBase: 最后一章数据解析完成,解析页面数为{0}"
, pages.length));
debug.info(self.format(
"PageBase: 初始化数据解析完成, 前章索引{0} 前章页数{1} 当章索引{2} 当章页数{3} "
, self.pPages.idx , self.pPages.length , self.cPages.idx , self.cPages.length ));
debug.info(
"PageBase: 初始化数据解析完成,即将生成结构操作!"
);
});
deferred.all([prev , curr]).then(self.steup.bind(self));
});
}
else
{
debug.info(
"PageBase: 初始化入口点从中间章开始进入"
);
prev = self.loadPrevData(idx - 1);
debug.info(
"PageBase:解析器解析中间章的前一章数据!"
);
prev.then(
function
(args){
self.pPages = args.pages ;
self.pPages.idx = args.index;
debug.info(self.format(
"PageBase: 中间章前一章数据解析完成,解析页面数为{0}"
, args.pages.length));
debug.info(
"PageBase:解析器解析中间章数据!"
);
curr = self.process(self.chapters[idx]);
curr.then(
function
(pages , data){
if
(self.isChangeFont){
self.idx = Math.ceil((pages.length) * self.idx);
// console.log("spages.length - 1",pages.length)
// console.log("self.idx",self.idx)
}
self.cPages = pages ;
self.cPages.idx = idx;
debug.info(self.format(
"PageBase: 中间章数据解析完成,解析页面数为{0}"
,pages.length));
debug.info(
"PageBase:解析器解析中间章的后一章数据!"
);
next = self.loadNextData(idx + 1);
next.then(
function
(args){
self.nPages = args.pages ;
self.nPages.idx = idx + args.index;
debug.info(self.format(
"PageBase: 中间章后一章数据解析完成,解析页面数为{0}"
, args.pages.length));
debug.info(self.format(
"PageBase: 初始化数据解析完成, 前章索引{0} 前章页数{1} 当章索引{2} 当章页数{3} 下章索引{4} 下章页数{5}"
, self.pPages.idx , self.pPages.length , self.cPages.idx , self.cPages.length , self.nPages.idx , self.nPages.length));
debug.info(
"PageBase: 初始化数据解析完成,即将生成结构操作!"
)
});
deferred.all([prev , curr , next]).then(self.steup.bind(self));
});
});
}
|
但是对于异步+回调的模式,当需要对一系列异步操作进行流程控制的时候似乎必然会面临着回调嵌套。因此怎么把异步操作“拉平”,用更好的方法去优化异步编程的体验,同时也写出更健壮的异步代码,是这两年来前端圈子里很火的话题。
代表的
本人在项目中使用 Promise/A 规范实现的 deferred-js , 比较简单轻巧.
如何使用?
API:
var
DeferredAPI = {
deferred : deferred,
all : all,
Deferred : Deferred,
DeferredList : DeferredList,
wrapResult : wrapResult,
wrapFailure : wrapFailure,
Failure : Failure
}
|
//Deferred对象创建 var d = new deferred.Deferred() //添加一个回调到递延的回调链 d.then(function(result) { console.log('Hello ' + result) return result }) //等待回调后触发 d.resolve('World')
每个链接在一个回调链可以是两个函数,代表一个成功,一个失败
d.then(function(result) { // 自己的代码 return result })
d.fail(function(failure) { // optionally do something useful with failure.value() return failure });
d.then(function(result) { // do something useful with the result return result }, function(failure) { // optionally do something useful with failure.value() return failure })
d.both(function(result) { // in the case of failure, result is a Failure // do something in either case return result })
请仔细对照下案例中的
deferred.all([prev , curr , next]).then(self.steup.bind(self));
all的方法等待所有的延时队列加载完毕后,才执行后续代码
使用起来很方便,很精简没有那么多复杂的概念
使用教程之后,下一节附源码的实现