如何从生成器函数调用的异步回调中产生?

时间:2016-02-10 06:47:45

标签: javascript node.js asynchronous generator yield

我只是在学习node.js生成器,并且我希望生成器从生成器调用的异步方法的回调中获得一个值。以下代码是我当前的示例。第一个生成器(get_urls)返回网站某些页面的一系列URL。它工作正常。

第二个生成器应该使用unirest来检索每个网页,以便生成器可以返回页面内容。但是,我无法弄清楚如何从unirest.end()函数的回调中产生。

有些库可以更全面地执行此操作(并且具有更好的错误处理),但我正在尝试理解最低级别,以便在我足够聪明地使用它们时可以从库中获得更多。

#!/usr/local/bin/node
// -*- mode: Javascript; -*-

var unirest = require( 'unirest' );

for (var url of get_urls( 'http://www.example.com/generated-page?n=1' ))
    console.log( 'Get url', url );

for (var page of get_pages( 'http://www.example.com/generated-page?n=1' ))
    console.log( 'Got page', page );

function* get_urls( url ) {
    do {
        yield url;
        var rx = url.match( /^(.*?n=)([0-9]+)$/ );
        if (rx) {
            if (rx[2] >= 3) break;
            url = rx[1] + (parseInt(rx[2]) + 1).toString( );
        }
    } while (rx);
}

function* get_pages( url ) {
    do {
// *** This is what I want to do, but it's not the right way to do it! ***
//      unirest.get( url ).end( function (rsp) { yield rsp; } );
        var rx = url.match( /^(.*?n=)([0-9]+)$/ );
        if (rx) {
            if (rx[2] >= 3) break;
            url = rx[1] + (parseInt(rx[2]) + 1).toString( );
        }
    } while (rx);
}

1 个答案:

答案 0 :(得分:0)

yield只能屈服于立即包含它的生成器function*。因此,您不能从回调中屈服。

您可以通过回调来解决Promise,您的生成器函数可以产生该Promise。

您的答案有很多无关的代码(加上native Fetch等时为什么还要使用unirest),因此这里有一个示例(来自我的another answer),说明了产生承诺的概念反复:

async function* fetchUrls() {
  let i = 0;
  while (i < 10)
    yield new Promise((resolve, reject) => {
      setTimeout(() => resolve(i++), 200);
    });
}

(async function main() {
  // for-await-of syntax
  for await (const result of fetchUrls())
    console.log(result);
}());

新的for-await-of语法自Node v9.2起可用,并且可以在Node v10或更高版本中使用而没有任何标志。