Skip to content

Instantly share code, notes, and snippets.

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