译者:Herylee
让我们通过使用请求库实际使用案例。
步骤 1: 回调地狱 - N层深
这就是典型的NodeJS代码的样子。每一个函数会获取一个具有常用的签名的回调函数: function(err, response){ }
步骤 2: Promises - 1层深
Promise库需要典型的回调函数: function(err, response) { } 然后将这些参数分离成then/catch链式回调 .then(function(response) { }).catch(function(err) { })
你可以使用Q, 或者其他可以用的promise库。我已经在这里使用bluebird。你必须先“promisify“旧式回调库的方法。
说明你如何必须使用“request.getAsync”代替“request.get”。这就称为“promisification” (line #2) - 它将正则方法转换为promise式的方法。而且说明了简化调用foo()的过程。
step 3: Promises+Generators - 0层
让我们结合promises和ES6 generators的力量。
现在“foo”几乎是连续的。我们从callback 类型减少到promises的23行,再到promises + generators的19行。它看起来完全没有嵌套函数的平坦。当然,幕后仍有回调发生,但所见即所得。
请注意,我们称之为“foo”的地方仍然使用promises。我们可以使用generators扁平化,这样它成为一个简单的尝试/捕获。
function* callerFunction() {
try {
message = yield foo();
console.log(""success!"", message);
} catch (err) {
console.log(""error!"", err);
}
}
callerFunction = Promise.coroutine(callerFunction);
callerFunction();
和你所在的地方叫“调用函数”也可以是扁平的,等等,等等,直到最顶层的应用程序入口点。对于Web应用程序,该入口点是Web框架。如果Web框架意识到使用generators和promises,你可以基本上使所有的函数作为generator和永远的扁平化。那么你将接近的一些内容像koa。
转化测试
在写(Mocha等)测试时Generators非常有用。测试通常有很多回调,但是他们按顺序运行。这是浪费异步性。你可以今天使用Generators编写测试案例,不用担心变换测试框架。
步骤 4: ES7 async/await
ES7 async/await 是在generators的上面运作。Babel已经运行中(尽管它仍然在测试阶段),因此你可以今天尝试。
等等,它是如何工作的?
这整个魔幻简单的运作是由于NodeJS回调函数有一个标准的签名 function(err, response) { }。
Promise 库仅仅在你的代码间,目标函数 (request.get/post/…)和延迟对象间担任粘连作用,
deferred = // create a Deferred() object
customCallback = function(err, response) {
if (err) deferred.reject(err);
else deferred.resolve(response);
}
// call original request.get/post/... with customCallback
// return you the Deferred's promise
当ES6引入generators,Promise库象征着黑客钩连在一起:如果你“生成一个promise”,你会得到返回的解析值。
`**try {**`
**response = yield request.getAsync(...)**
^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
_to get the response_ _yield a promise_
**} catch (error) { }**
^^^^^^^^^^^^^^^^^^^^^
_catch the error_
Generators如何工作是一个更大的话题。我建议你阅读davidwalsh.name/es6-generat… 或者网上大量的文章。