Skip to content

Instantly share code, notes, and snippets.

@stableShip
Last active November 20, 2015 03:30
Show Gist options
  • Save stableShip/eeae7809d653452c0139 to your computer and use it in GitHub Desktop.
Save stableShip/eeae7809d653452c0139 to your computer and use it in GitHub Desktop.
js异步流程控制
#js异步流程控制
##为什么会有异步流程控制
###1.使用callback
错误处理:传统的try/catch形式无法捕获到callback中的错误
回调地狱:使用callback会造成回调地狱.
```
doAsync1(function () {
doAsync2(function () {
doAsync3(function () {
doAsync4(function () {
...
})
})
})
```
###2.使用事件监听:
另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
还是以f1和f2为例。首先,为f1绑定一个事件。
`f1.on('done', f2);`
上面这行代码的意思是,当f1发生done事件,就执行f2
这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合"(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰,无法调试.
###3.发布/订阅
上一节的"事件",完全可以理解成"信号"。
我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。
首先,f2向"信号中心"jQuery订阅"done"信号。
`jQuery.subscribe("done", f2);`
向"信号中心"jQuery发布"done"信号,就会执行f2函数
`jQuery.publish("done");`
f2完成执行后,也可以取消订阅(unsubscribe)。
  `jQuery.unsubscribe("done", f2);`
这种方法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
##异步流程控制
###promise:
Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。
简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。比如,f1的回调函数f2,可以写成:
`f1().then(f2);`
这样写的优点在于,回调函数变成了链式写法,程序的流程可以看得很清楚,而且有一整套的配套方法,可以实现许多强大的功能。
比如,指定多个回调函数:
`  f1().then(f2).then(f3);`
如果一个任务已经完成,回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号。这种方法的缺点就是编写和理解,都相对比较难。
Promise 的写法只是回调函数的改进,使用then方法以后,异步任务的两段执行看得更清楚了,除此以外,并无新意。
###thunk:
一种将会掉函数返回的形式
```
function readFile(fileName){
return function (callback){
return fs.readFile(fileName, callback);
};
};
var readFileThunk = readFile(fileName);
readFileThunk(callback);
```
fs 模块的 readFile 方法是一个多参数函数,两个参数分别为文件名和回调函数。经过转换器处理,它变成了一个单参数函数,只接受回调函数作为参数。这个单参数版本,就叫做 Thunk 函数。
Thunk 函数有什么用?回答是以前确实没什么用,但是 ES6 有了 Generator 函数,Thunk 函数现在可以用于 Generator 函数的自动流程管理。
var gen= function* (){
var r1 = yield readFile('test.json');
console.log(r1.toString());
var r2 = yield readFile('test1.json');
console.log(r2.toString());
};
var g = gen();
g.next() //test.json
g.next() // test1.json
yield 返回了{value: someValue ,done: boolean }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment