ES6 yield多个生成器

6
在ES6中,yield和生成器函数允许等待一次函数执行。但我想等待多个生成器。
以下是代码:
files.forEach(function* (file) {
    const uploadedFile = yield call([service, service.upload], file, config)
}

callredux-saga效果。

为了表达Saga逻辑,我们从生成器中产生纯JavaScript对象。我们称这些对象为Effects。

我想一次性启动所有上传,而不必等待前一个上传完成,等到所有文件都上传完成后再等待一次,使用yield是否可行?


这取决于call是什么,这需要解释。如果你正在使用co或其他类似的东西,你可以使用Promise.all。你不能对yieldable本身这样做,只是因为生成器的本质。它们被yield“暂停”。 - Estus Flask
@estus call 是来自 redux-saga 库的效果创建函数 https://github.com/redux-saga/redux-saga - Sergiy Kozachenko
那么问题应该提到这一点,因为这完全取决于该生成器来自何处。请参阅http://stackoverflow.com/help/mcve 。call(...)的结果是什么?如果它是一个Promise,那么答案适用。如果不是,那就不适用。 - Estus Flask
@estus 将其添加到问题中。 - Sergiy Kozachenko
2个回答

7
我正在寻找的实际上是这个:

// correct, effects will get executed in parallel
const [users, repos]  = yield [
  call(fetch, '/users'),
  call(fetch, '/repos')
]

call 在这里只是返回一个 promise。

当我们 yield 一个 effects 数组时,生成器会被阻塞,直到所有的 effects 都得到解决或者其中一个被拒绝(就像 Promise.all 的行为一样)。


1
你可以使用Promise.all()代替。 例子: 如果你想要在所有上传完成后触发它们并重新控制代码,你可以使用async/await接口:
function uploadALL(files){
  const uploadedFilesPromises = files.map( file => {
    return call([service, service.upload], file 
  })        
  }
  return Promise.all(uploadedFilesPromises);
} 

// samples of using this function:
uploadALL(files).then((uploadedFiles)=> { ....  })
// or in async function you can use await:
const uploadedFiles = await uploadAll(files)

你的 "call" 方法应该返回一个 Promise 对象,否则你必须将其包装成 Promise。


也许你可以根据提问者的示例代码将其写出来。 - trincot
@AlexeyKuznetsov如果不使用async/await而是使用生成器,它将如何工作? - Sergiy Kozachenko
@Grievoushead 如果没有async/await,你只需要使用我第一个示例中的方法,uploadALL仍然返回Promise,而且不需要是async的(我已经编辑了我的代码示例)。在这里根本不需要使用生成器,只需要使用Promises即可。 - AlexeyKuznetsov
@AlexeyKuznetsov 这里的问题在于您假设生成器是基于 Promise 的(就像 co 库一样)。但事实并非如此。 - Estus Flask
1
@estus 我认为他们是根据redux-saga文档的:Sagas可以以多种形式产生效果。最简单的方法是产生一个Promise。但我知道通过Promise.all的解决方案,只是好奇是否有一些生成器的方式。 - Sergiy Kozachenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接