使用生成器进行异常处理

17

最近NodeJS中推出了生成器函数,我现在可以这样做:

Promise.coroutine(function *(query){
    var handle = yield db.connect(Settings.connectionString); //async, returns promise
    var result = yield db.query(query); // async, returns promise
    return result;
});

现在生成器非常棒,因为它们让我在JS中使用异步/等待。我真的很喜欢能够做到这一点。

然而,一个问题出现了。生成器与try / catch块一起使用,所以假设我有像这样的代码:

Promise.coroutine(function *(){
    try{
        var db = yield DBEngine.open("northwind"); // returns promise
        var result = yield db.query("SELECT name FROM users"); // returns promise
        return res;
    } catch (e){
        //code to handle exception in DB query
    }
});

(注意,Promise.coroutine来自bluebird

注意到问题了吗?有一个引用错误,但是catch会将其吞掉。

在大多数情况下,当我使用try/catch时,我想要捕获的是逻辑错误和I/O错误,而不是语法或类型错误。我想要非常非常地注意这些错误。回调函数使用一个err作为第一个参数,在生成器中我不确定替代方法是什么。

如何在JavaScript的生成器代码中处理异常?

一个好的解决方案应该允许我保留堆栈跟踪。


3
你已经知道应该检查错误并重新抛出它。 - Esailija
你能返回错误本身吗? - dandavis
@dandavis 我不确定你的意思是什么。 - Benjamin Gruenbaum
2个回答

10
基本上,这与异步系统无关,而是与特定的错误处理有关。尝试像这样做:
``` 所以基本上这个问题不是与异步系统相关,而是与特定的错误处理有关。可以尝试像下面这样处理: ```
var global_error_check = function(e) {
    if (e && e.name === "ReferenceError") {
        throw e;
    }
    // put other error types here that you don't want to catch
}

try {
    ...
} catch(e) {
    global_error_check(e);
    // handle other errors here
}

经过深思熟虑,我很遗憾,这是唯一明智处理此事的方法。 - Florian Margaine

3
根据最新的ES6生成器草案,您可以调用生成器的“throw”函数来使用抛出的错误恢复生成器。
例如:
function procrastinatingAdd(x, y) {
  var errMsg = "Expected number and got ";
  setTimeout(function() {
    if (isNaN(x)) gen.throw(new TypeError(errMsg + typeof x));
    if (isNaN(y)) gen.throw(new TypeError(errMsg + typeof y));
    gen.next(x + y);
  }, 500);
}

var gen = function* () {
  try {
    var result = yield procrastinatingAdd(1, "foo");
    log(result);
  }
  catch (e) {
    log(e);
  }
};

gen = gen();
gen.next();

我假设你使用的库来管理生成器中的流程控制(我没有研究过 Promises,但是像 gennygen-run 这样的库)应该可以为你处理这个问题,以便你所使用的库不需要了解生成器。


6
gen = gen(); 这行代码非常糟糕。 - caub

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