什么时候抛出(错误)和返回(值)在javascript迭代器中有用?

什么时候抛出(错误)和返回(值)在javascript迭代器中有用?,javascript,iterator,redux-saga,Javascript,Iterator,Redux Saga,在javascript中,迭代器可以有throw(error)和return(value)方法return(value)使迭代器有机会查看value,并应返回{value:value,done:true}抛出(错误)使迭代器有机会看到并可能捕获错误。如果捕获到错误,throw应返回下一个值。如果未捕获异常,则它应等同于返回(未定义)。下面是这些机制的一个例子: 函数*test(){ 试一试{ 产量1; }捕获(e){} 消费者成本=收益率2; 来自消费者的收益; //我不知道如何访问传递给生成器

在javascript中,迭代器可以有
throw(error)
return(value)
方法
return(value)
使迭代器有机会查看
value
,并应返回
{value:value,done:true}
<代码>抛出(错误)使迭代器有机会看到并可能捕获错误。如果捕获到错误,
throw
应返回下一个值。如果未捕获异常,则它应等同于
返回(未定义)
。下面是这些机制的一个例子:

函数*test(){
试一试{
产量1;
}捕获(e){}
消费者成本=收益率2;
来自消费者的收益;
//我不知道如何访问传递给生成器返回的值
}
const iter=test()[Symbol.iterator]();
log(iter.next());
log(iter.throw(新错误('catch me'));
console.log(iter.next(9));
log(iter.next());
控制台日志(iter.return(0));
(和a一样)

我的问题是:为什么?有人对迭代器的这种控制API反转有一个合理的用例吗?在什么条件下,迭代器处理在使用它时发生的错误是有意义的?如果确定要结束迭代器并且不能进一步影响迭代器API的行为,您希望何时传递一个返回值


我要说的是,我所知道的一个用例是redux saga,他们利用了迭代器的控制API反转,似乎是穷人的异步/等待。如果有人熟悉该工具的设计或使用,他们的选择还有其他好处吗?

首先,并不是所有迭代器都有返回和抛出功能。迭代器唯一需要的是
next
。但生成器函数创建的迭代器确实有
返回
抛出

我要说的是,我所知道的一个用例是redux saga,他们利用了迭代器的控制API反转,似乎是穷人的异步/等待

我认为这是倒退。生成器不是async/await的糟糕版本;async/await是生成器的狭义用法。事实上,async/await的旧等价物实际上是使用生成器实现的,如在库中找到的那样。既然异步/等待是核心语言的一部分,我不知道底层C++代码是否真的使用了生成器,但从历史上和概念上来说,它是与解决承诺的狭义案例相联系的生成器的产物。 使用像redux saga这样的库,不仅可以获得类似await的语法,还可以支持更复杂的事情,例如任务取消,这是async/await无法做到的。任务取消取决于
返回
的工作方法。还支持错误处理,这可以通过
throw
方法实现

因此,生成器是一个非常广泛的工具,除其他外,它可以用来建模异步行为。因为它们的范围很广,所以它们附带了一组函数,这些函数不仅能够对迭代进行建模。我认为生成器不仅仅是一种迭代方式,而是在两段代码之间进行双向对话。在你可能想要传达的事情中,有一件事是“有问题”或“我们到此为止”,这就是掷球和回击的目的

如果确定要结束迭代器并且不能进一步影响迭代器API的行为,您希望何时传递一个返回值

实际上,它仍然可以影响它。如果生成器使用try/finally,
.return()
会将生成器发送到finally块,在那里它可以运行任意数量的代码。生成器甚至可以在这个finally块中屈服,其行为与finally块之前相同。继续以redux saga为例,生成器的这个特性用于在取消时支持回滚

function* exampleSaga() {
  try {
    // start working on something, with at least one yield
  } finally {
    if (yield cancelled()) {
      // roll back
    }
  }
}

以下是我到目前为止的想法:

与使用async/await与远程代码交互相比,将代码编写为协同程序操纵的生成器具有以下优势:

  • 协同程序可以在生成器上使用三种潜在的反馈路径:
    产生
    抛出
    、和
    返回
    ,而不仅仅是
    解决
    拒绝
    <代码>返回在这种情况下,表示普通承诺中不可用的on选项,即取消

  • 与async/await不同,不要求传输控制流将导致异步性。这允许协程选择控件是同步继续还是异步继续,并允许它检查生成的值,如果它们不可用,则立即使用它们


  • 最后,关于生成器何时适合捕获消费者的错误,答案是:当消费者是一个协同程序,在执行生成器指示的操作时遇到错误,在这种情况下,生成器,作为导致错误的操作的来源,也应该了解如何处理它。

    我没有时间对此给出正确的答案,并且怀疑有人会说这个问题过于开放或基于观点(什么是“可辩护的”用例?)。虽然迭代器允许有
    返回
    抛出
    ,但它们真正有用的地方是生成器。使用生成器,您可以构建协同程序。协同程序不仅仅是“穷人的
    异步
    /
    等待
    ”“通常,这些方法的调用方应该在调用它们之前检查它们是否存在。某些ECMAScript语言功能,包括of、
    yield*
    和数组解构,在执行存在性检查后调用这些方法。大多数接受Ite的ECMAScript库函数