我已经阅读了 ECMAScript 6 附带的生成器,并且已经在 node.js 开发版本中可用,它将更容易以同步方式编写异步代码。但是对我来说真的很难理解,我们如何使用生成器来编写异步代码?
2 回答
我们首先要记住,使用 ES 生成器,我们可以向next()
方法传递一个值,这将是生成器中的 yield 语句的返回值。
这个想法是将生成器赋予一种控制器功能。
在生成器中,每次调用异步函数时,yield
我们都会将控制权交还给控制器函数。控制器函数除了next()
在异步操作完成时调用之外什么都不做。在这段时间内,我们可以处理其他事件,所以它是非阻塞的。
没有生成器的示例:
// chain of callbacks
function findAuthorOfArticleOfComment (commentID, callback) {
database.comments.find( {id: commentID}
, function (err, comment) {
if (err) return callback(err);
database.articles.find( { id: comment.articleID }
, function (err, article) {
if (err) return callback(err);
database.users.find( { id: article.authorID }
, function (err, author) {
if (err) return callback(err);
callback(author);
});
});
});
}
findAuthorOfArticleOfComment (commentID, function(err, author) {
if(!err) console.log(author);
}
生成器示例:
如果您想将其与 Promises 一起使用,我们必须使用一个可以控制流程的库,例如suspend或bluebird 。为了更好地理解,我将举一个没有库的例子。
function* myGenerator(resume, commentID, callback) {
var comment, article, author;
comment = yield database.comments.find( {id: commentID}, resume);
article = yield database.articles.find( {id: comment.articleID}, resume);
author = yield database.users.find( {id: article.authorID}, resume);
};
// in real life we use a library for this !
var findAuthorOfArticleOfComment = function(commentID, callback) {
var resume, theGenerator;
resume = function (err, result) {
var next;
if(err) return callback(err);
next = theGenerator.next(result);
if (next.done) callback(null, result);
}
theGenerator = myGenerator(resume, commentID, callback);
theGenerator.next();
}
// still the same function as first example !
findAuthorOfArticleOfComment (commentID, function(err, author) {
if(!err) console.log(author);
}
我们所做的 :
- 创建生成器,给一个恢复函数作为第一个参数,一个由函数调用者给出的参数
next()
第一次打电话。我们的第一个异步函数到达并且生成器产生了。- 每次
resume
调用该函数时,我们获取值并将其传递给 next,因此生成器中的代码继续执行并且 yield 语句返回正确的值。
在现实生活中,我们将使用一个库,并将生成器作为参数提供给通用控制器函数。所以我们只需要编写生成器和value = yield asyncFunction(parameters, resumeCallback);
, 或者value = yield functionReturningPromise(parameters);
如果您使用 Promises(带有 Promise 兼容库)。这确实是一种以同步方式编写异步代码的好方法。
优秀来源:
http ://tobyho.com/2013/06/16/what-are-generators/ http://
jlongster.com/A-Closer-Look-at-Generators-Without-Promises
作为 Guilro 的回答,生成器允许您编写如下内容:
controllerFunction(function*() {
yield functionThatReturnsAThenable()
yield anotherFunctionThatReturnsAThenable()
return;
});
控制器函数所做的是调用生成器,获取它从 yield 中返回的任何内容,链接对返回值的next()
调用,直到生成器为.then()
done
像这样的东西:
function controllerFunction(generator) {
function run(runnableGenerator) {
var result = runnableGenerator.next(); // or send(params)
if (!result.done) {
if (result.value.then) {
result.value.then(function() {
run(runnableGenerator);
});
} else {
run(runnableGenerator);
}
}
}
var runnableGenerator = generator();
run(runnableGenerator);
}