0

我已经阅读了 ECMAScript 6 附带的生成器,并且已经在 node.js 开发版本中可用,它将更容易以同步方式编写异步代码。但是对我来说真的很难理解,我们如何使用生成器来编写异步代码?

4

2 回答 2

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 一起使用,我们必须使用一个可以控制流程的库,例如suspendbluebird 。为了更好地理解,我将举一个没有库的例子。

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://
jlong​​ster.com/A-Closer-Look-at-Generators-Without-Promises

于 2014-02-09T19:28:47.233 回答
0

作为 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);

}
于 2014-10-28T16:44:37.767 回答