非 Promise 方式Wind.js 介绍 是 IBM 高级咨询师 的 ,引用他的话来说,是希望通过 JavaScript 这门语言体现 F# 中“计算表达式”特性,来达到简化异步编码的目的。基于 Wind.js 实现本文第一个例子,代码如下:
清单 4.基于 Wind.js 实现本文第一个例子的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
| var asyncTask = eval(Wind.compile("async", function (idx) { // 运行“编译”后的代码', 得到句柄
for (var i=0; i<5; i++) {
$await(Wind.Async.sleep(2000)); // 等待2秒再继续执行
var result = parseInt(Math.random() * 100, 10) % 2,
time = (new Date()).getTime(),
prefix = "Wind.js " + time + " " + i + ":";
if (result == 0) {
console.info(prefix + "got an even number");
} else {
console.info(prefix + "got an odd number");
}
}
}));
asyncTask().start(); // 开始运行异步任务
|
图 3.清单 4 中代码的运行结果 由于使用了$await(Wind.Async.sleep(2000)) 这行代码,我们实现了每 2 秒获得一个奇数或者偶数。好奇的读者也许想知道 Wind.js 运行原理,简单的说,Wind.js 先对源代码进行词法分析、语法分析,然后动态生成新代码以实现异步编程。
需求实现
同样还是员工场景的那三个关键方法,我们将用到 Wind.js 的 Wind.Async.Task 类,将回调写法的代码封装起来,代码示例如下:
清单 5.从服务端获取员工列表数据的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| Employee.all = function(opt) {
var opt = opt || {local: true}, Task = Wind.Async.Task;
if (opt.local === true) {
throw new Error('not implemented!');
} else {
return Task.create(function(t) { // 创建 Wind.Async.Task实例, 封装必须使用回调方法的代码
$.ajax({
url: "/async/api/employee",
dataType: "json"
}).then(function(items) {
var employees = [];
$(items).each(function(idx, item) {
employees.push(new Employee(item))
});
t.complete("success", employees); // 操作成功
}, function(err) {
t.complete("failure", err); // 操作失败
});
});
}
};
|
清单 6.实现模拟场景的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| $(document).ready(function() {
var employeeTask = eval(Wind.compile("async", function (idx) { // 生成句柄
try {
var employees = $await(Employee.all({local: false})); // 通过$await方法以便”编译”
for (var i=0; i<employees.length; i++) {
var employee = employees;
if (employee.age >= 30) {
var employeeWithDetail =
$await(Employee.get(employee.id, {local: false}));
$await(employeeWithDetail.create({local: true}));
} else {
$await(employee.create({local: true}));
}
}
} catch(err) {
console.error(err);
}
}));
employeeTask().start();
});
});
|
从清单 6 的代码不难看出,这种代码风格已经看不到 JavaScript 中常用的回调写法,毫无疑问,开发者会更容易接受这种“顺序执行”编程体验。
JSDeferred 介绍 则是一款独立、简洁的异步执行类库,通过 next、loop、call、parallel 和 wait 等方法实现异步编程。依然是基于 JSDeferred 改写本文第一个例子,代码如下:
清单 7.基于 JSDeferred 实现本文第一个例子的代码1
2
3
4
5
6
7
8
9
10
11
12
| Deferred.define(); // 将JSDeferred的方法变成全局方法
loop(5, function (i) { // 顺序循环5次
var result = parseInt(Math.random() * 100, 10) % 2,
time = (new Date()).getTime(),
prefix = "JSDeferred " + time + " " + i + ":";
if (result == 0) {
console.info(prefix + "got an even number");
} else {
console.info(prefix + "got an odd number");
}
return wait(2); // 等待2秒
});
|
图 4.清单 11 中代码的运行结果 由于篇幅限制,下面只列出 JSDeferred 实现模拟场景的代码:
清单 8.实现模拟场景的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| $(document).ready(function() {
Deferred.define();
next(function () {
return Employee.all({local: false}); // 当从远端获得所有员工数据时,才运行下一步
}).
next(function (employees) {
return loop(employees.length, function(i) { // 顺序遍历员工
var employee = employees;
if (employee.age >= 30) {
return Employee.get(employee.id, {local: false})
.next(function(employeeWithDetail) {
return employeeWithDetail.create({local: true});
}); // 从远端获取员工明细,保存到本地
} else {
return employee.create({local: true});
}
})
}).
error(function(err) {
console.error(err); // 异常会导致异步过程中断,并被打印
})
});
|
由此可见,在改善异步编程体验方面,已经是百花齐放的局面,对于其他改善异步编程体验的方式,本文不一一罗列,感兴趣的读者可自行了解。 |