Обработка исключений с генераторами

Так недавно генераторы вступили в 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;
});

Теперь генераторы являются удивительными, поскольку они позволяют мне делать async/await в 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)

Обратите внимание на ошибку? Однако есть ссылочная ошибка - улов проглотит ее.

Когда я помещаю try/catch в 95% случаев, то, что я хочу поймать, это логические ошибки и ошибки ввода-вывода, а не синтаксис или ошибки типа. Я хочу очень хорошо знать об этом. Обратные вызовы используют первый параметр err, а в генераторах я не уверен, что такое замена.

Как мне работать с обработкой исключений в коде генератора в JavaScript?

Хорошее решение позволило бы мне сохранить следы стека.

Ответы

Ответ 1

Таким образом, в основном это не связано с асинхронной системой, а скорее с конкретной обработкой ошибок. Попробуйте что-то вроде этого:

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
}

Ответ 2

Согласно самому последнему проекту 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, но libs вроде genny и gen-run) должны обрабатывать это для вас, чтобы библиотеки, которые вы потребляли, не нуждались в генераторе.