2015-04-17 31 views
5

我正在用babel的帮助试验ES6生成器,并且我很难理解如何(或者如果!)我可以有效地使用基于回调的异步函数来输出迭代器。ES6生成器:将回调转换为迭代器

比方说,我希望能够编写一个函数,它需要一些url,异步地下载它们并在它们被下载后立即返回。 我希望能够写出像下面这样:

let urls = ['http://www.google.com', 'http://www.stackoverflow.com' ]; 
for ({url, data} of downloadUrls(urls)) { 
    console.log("Content of url", url, "is"); 
    console.log(data); 
} 

我怎样才能实现downloadUrls? 理想我想能写:

var downloadUrls = function*(urls) { 
    for(let url of urls) { 
     $.ajax(url).done(function(data) { 
      yield data; 
     }); 
    } 
}; 

这当然是不行的,因为``产量'被调用的回调中,而不是直接在发生器内。 我可以在网上找到很多试用相同的例子,它们是not much transparent),需要enabling browser/node flags,或者使用节点特定的功能/库。 最接近我需要的库似乎是task.js,但我无法在当前的Chrome上运行最简单的示例。

有没有一种方法可以使用标准和当前功能获得预期的行为,(目前我的意思是可用于像babel这样的转译器,但不需要在浏览器上启用额外的标志)还是必须等待async/await

+0

这些在线解释到底对您而言“不透明”究竟如何?大卫沃尔什文章是我读过的最好的文章之一(但你需要阅读整个课程系列) – Bergi

+0

似乎相关:异步生成器提议https://github.com/jhusain/asyncgenerator(不支持任何地方据我所知)。 –

回答

1

有没有办法使用标准和当前功能

是,使用的承诺和发电机,以获得预期的行为。许多承诺库和一些独立版库都使用了发生器“协同程序”。

但请注意,you cannot mix iteration with asynchrony,您可以只使用发生器。你的例子似乎混淆了他们 - 它看起来像你期望for ({url, data} of downloadUrls(urls)) {循环同步工作,这是行不通的。

我需要等待async/await

不,您不必等待,Babel already supports them

1

这里是使用一个发电机/迭代器扁平化异步代码在node.js中工作对我来说是干净的方法:

var asyncProcedureGenerator1 = function*() { 
    var it = yield(0); //get a reference to the iterator 
    try { 
     var a = yield (asyncPart1.bind(it))(0); //call the function, set this = it 
     var b = yield (asyncPart2.bind(it))(a); 
     var c = yield (asyncPart3.bind(it))(b); 
     console.log("c = ", c); 
    } 
    catch(err) 
    { 
     console.log("Something went wrong: ", err); 
    } 
}; 

var runAsyncGenerator = function(generator) { 
    var asyncProcedureIterator = generator(); //create an iterator 
    asyncProcedureIterator.next(); //start the iterator 
    asyncProcedureIterator.next(asyncProcedureIterator); //pass a reference of the iterator to itself 
} 

var asyncPart1 = function(param1) { 
    var it = this; //the iterator will be equal to this. 
    console.log("Starting asyncPart1 with param1 = ", param1); 
    setTimeout(function() { 
     console.log("Done with asyncPart1"); 
     var returnValue = 42 + param1; 
     console.log("asyncPart1 returned ", returnValue); 
     it.next(returnValue); //when we are done, resume the iterator which has yielded to us. 
    },2000); 
}; 

var asyncPart2 = function(param1) { 
    var it = this; //the iterator will be equal to this. 
    console.log("Starting asyncPart2 with param1 = ", param1); 
    setTimeout(function() { 
     console.log("Done with asyncPart2"); 
     var returnValue = param1/2; 
     console.log("asyncPart2 returned ", returnValue); 
     //it.throw("Uh oh."); 

     it.next(returnValue); 

    },2000); 
}; 

var asyncPart3 = function(param1) { 
    var it = this; //the iterator will be equal to this. 
    console.log("Starting asyncPart3 with param1 = ", param1); 
    setTimeout(function() { 
     console.log("Done with asyncPart3"); 
     var returnValue = param1/3; 
     console.log("asyncPart3 returned ", returnValue); 
     it.next(returnValue); 
    },2000); 
}; 

runAsyncGenerator(asyncProcedureGenerator1); 

的想法是运行发电机,创作者的迭代器,然后通过该迭代器对其自身的引用。

然后迭代器可以调用异步函数(带有yield)并将它们传递给自身,从而允许这些函数通过调用iterator.throw()返回成功并恢复执行,方法是调用iterator.next(result)错误)。

我刚刚想出了这个模式,所以可能有一些我还没有找到的问题,但它似乎工作,并允许很少添加很平的代码。

相关问题