我已经读过,ECMAScript 6附带并且已经在node.js开发版中提供的生成器将更容易以同步方式编写异步代码。但是我真的很难理解,我们如何使用生成器编写异步代码?
答案 0 :(得分: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语句返回正确的值。在现实生活中,我们将使用库,并将生成器作为参数提供给通用控制器函数。因此,我们必须编写的是生成器,如果使用Promises(与Promise兼容的库),则value = yield asyncFunction(parameters, resumeCallback);
或value = yield functionReturningPromise(parameters);
。这是以同步查找方式编写异步代码的好方法。
优秀来源:
http://tobyho.com/2013/06/16/what-are-generators/
http://jlongster.com/A-Closer-Look-at-Generators-Without-Promises
答案 1 :(得分:0)
补充Guilro的答案,生成器允许你写这样的东西:
controllerFunction(function*() {
yield functionThatReturnsAThenable()
yield anotherFunctionThatReturnsAThenable()
return;
});
控制器函数执行的操作是调用生成器,获取从yield返回的任何内容,将next()
调用链接到返回值的then()
,直到生成器为done
。< / p>
这样的事情:
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);
}