异步模式在web编程中变得越来越重要,对于Javscript来说,异步编程要解决的问题有两个:一是必须通过回调函数进行返回值的处理
,另一个是复杂情况下会造成嵌套过深
。
目前,解决异步流程控制问题的主流方案有以下几种:
##1. 基于回调
适用于流程简单的情况,当出现过多回调的时候实现起来不是很利索,且容易使代码的可读性
和可维护性
下降。
var done = function(){
console.log("done");
};
var fail = function(){
console.log("fail");
};
// 通过参数的方式 传入回调函数并执行
var run = function(done, fail) {
setTimeout(function(){
Math.random() > 0.5 ? done() : fail();
}, 1000);
};
run(done, fail);
##2. Promise/Deferred 可以参考 这里
// 以 jQuery 为例
var wait = function() {
// 新建一个deferred对象
var dfd = $.Deferred();
var run = function() {
// 随机生成 deferred对象 的状态
var result = Math.random() > 0.5;
if (result) {
console.log("done() will be run...");
// 表示成功
dfd.resolve();
} else {
console.log("fail() will be run...");
// 表示失败
dfd.reject();
}
};
setTimeout(run, 1000);
// 返回 deferred 对象
return dfd.promise();
};
// 根据 resolve 和 reject 状态执行回调
$.when(wait())
.done(function() {
console.log("done...");
})
.fail(function() {
console.log("fail...");
});
##3. 基于自定义事件的监听 和回调很像,有些场景下可以做到比回调更好的逻辑分离
// 添加自定义事件 监听
$(document).on("done", function(){
console.log("done...");
}).on("fail", function(){
console.log("fail...");
});
// 同一事件 可以添加多个监听
// 这种方式有利于业务逻辑的分离和解耦
$(document).on("done", function(){
console.log("done2...");
});
setTimeout(function(){
// 通过trigger触发该事件执行
$(document).trigger(Math.random() > 0.5 ? "done" : "fail");
}, 1000);
##4. 基于编译器和eval 比如 Wind.js(原名Jscex),由于作者已经停止更新,故在次不多做介绍,有兴趣的可以看这里。
##5. 高阶函数篡改回调函数 参考 async 和 step
##6. 值得期待的ECMAScript6和Generator
Generator的中文翻译是生成器,它是ECMAScript6(代号harmory)中提供的新特性。在过去,封装一段运算逻辑的单元是函数。函数只存在“没有被调用”或者“被调用”的情况,不存在一个函数被执行之后还能暂停的情况,而Generator的出现让这种情况成为可能。
Node.js v0.11
以上版本支持,在命令行通过参数 --harmony-generators
启动
node --harmony-generators main.js
Generator 的定义十分简单,与普通的函数相比,它只多出一个*
号。以下为简单例子:
// 采用匿名函数定义
// 也可以才用 function* compute(a, b){} 的方式定义
var compute = function* (a, b) {
var sum = a + b;
console.log(sum);
var minus = a - b;
console.log(minus);
var mult = a * b;
console.log(mult);
var div = a / b;
console.log(div);
};
var generator = compute(4, 2);
// 调用next执行
generator.next();
// 输出
6
2
8
2
// 加入 yield 关键字
// 代码遇到 yield 将停止执行
// 调用 next 继续运行
var compute = function* (a, b) {
var sum = a + b;
yield sum;
var minus = a - b;
yield minus;
var mult = a * b;
yield mult;
var div = a / b;
yield div;
};
var generator = compute(4, 2);
// 调用next执行
// done 表示已执行完
// done 表示是否执行完
console.log(generator.next()); // { value: 6, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: 8, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: undefined, done: true }
也可以通过next传递参数
var compute = function* (a, b) {
var foo = yield a + b;
console.log(foo); // 输出 Hello world! 而不是 6
};
var generator = compute(4, 2);
console.log(generator.next()); // { value: 6, done: false }
console.log(generator.next("Hello world!")); // { value: undefined, done: true }
妈妈再也不用担心 JavaScript 没有 sleep
了,使用 Co ,可以用同步的方式写异步代码,世界又美好了。
good~