ES6生成器:来自iterator.throw的错误堆栈跟踪(错误)

时间:2015-05-17 18:29:59

标签: javascript ajax ecmascript-6 generator yield

ES6方法:iterator.throw(err)通常被描述为注入异常,就好像它发生在生成器中的yield语句中一样。问题是此异常的堆栈跟踪不包含对yield语句的文件/行的任何引用,甚至不包含对它所在的函数的引用。相反,堆栈跟踪似乎只在异常对象为构造,不在generator内。

问题是:如何以堆栈跟踪或其他方式获取有问题的yield语句的位置?

function* one_of_many_generators() {
    // ...
    yield ajax(url);    // <-- what I need in the stack trace
    // ...
}

function outer() {
    var iterator = one_of_many_generators();
    iterator.next();    // runs to the first yield

    // inject exception at the yield statement
    iterator.throw(Error("error"));   // <-- top of stack trace shows here
}

虽然此问题并非针对Promises,但它们可能会更容易描述问题。就我而言,我正在使用具有生成器和承诺的任务系统。假设函数ajax()返回一个Promise,如果拒绝,则使用此机制将错误转换为yield语句中的throw。

调试器中的堆栈跟踪非常无用,因为我无法找到发生此注入的 yield statement 的函数,文件或行号。调用iterator.throw(err)被视为重新抛出,并且不会获得新的堆栈信息,因此它只显示ajax()函数内的一个位置,该位置可以从许多地方调用,并在{{}中抛出一个新错误{1}}如上例所示,相同的抛出线显示所有错误。没有给出关于调试错误执行outer()函数的提示。

我使用Chrome v42

2 个答案:

答案 0 :(得分:0)

迭代器和承诺混合得不是很好(但是) - 你基本上会产生一个在循环之外失败的承诺。

你可以通过将promise的结果传递给生成器来解决这个问题,例如:

function* one_of_many_generators() {
    // ...
    var promiseResult = yield ajax(url);    // <-- what I need in the stack trace

    // Now we're back in the generator with the result of the promise
    if(notHappyWithResult(promiseResult))
        throw new Error('Reason result is bad');
    // ...
}

async function outer() {
    var iterator = one_of_many_generators();
    let prms = iterator.next();    // runs to the first yield

    // Wait for the promise to finish
    let result = await prms;

    // Pass the result back to the generator
    let whatever = iterator.next(result);
}

仅限:这是asyncawait所做的事情(这些关键字只是一个承诺生成器的语法糖,结果会被传回)并且如果你使用它们是常规的{{1会工作的。

try-catch主要是一种停止迭代的方法,而不是将异常注入其中 - 堆栈的顶部仍然是你创建iterator.throw的地方。

最后,Chrome即将推出async iterators - 这些功能非常强大,而且都是承诺的迭代。

答案 1 :(得分:0)

这种方法呢?

async function example() {
  const arrayOfFetchPromises = [
    fetch('1.txt'),
    fetch('2.txt'),
    fetch('3.txt')
  ];

  // Regular iterator:
  for (const item of arrayOfFetchPromises) {
    console.log(item); // Logs a promise
  }

  // Async iterator:
  for await (const item of arrayOfFetchPromises) {
    console.log(item); // Logs a response
  }
}

在这种情况下,for-awaitarray中取出每个项目,然后等待其解决。即使第二个响应尚未准备好,您也将获得第一个响应,但是您始终会以正确的顺序获得响应。您可以使用例如相同的旧.catch来简单地处理拒绝:)但是,已知这种模式易于发生未处理的拒绝。总有Promise.all ... Promise.all版本是:

const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);

我还建议您检查其中一些工具:iter-tools