用异步代码抛出/捕获错误的替代方法?

时间:2015-02-15 19:18:57

标签: javascript node.js exception asynchronous callback

我过去常常抛出一些错误类的实例,让它们被应用到应用程序的某个地方,以解决用户错误。

示例可能是验证用户名:

function validateUsername (username) {
    if (!/^[a-z0-9_-]{3,15}$/.test(username)) {
        throw new ValidationError('Please enter 3-15 letters, digits, -, and/or _.');
    }
}

$('#username').blur(function () {
    try {
        validateUsername($(this).val());
    } catch (x) {
        $('<p></p>').addClass('error').text(x).insertAfter(this);
    }
});

但是现在我意识到我不能将这些相同的做法用于异步调用。例如:

function checkUsernameAvailability (username) {
    $.get('/users/' + username).done(function () {
        // Done = user returned; therefore, username is unavailable
        // But I can't catch this error without resorting to something gross
        // like window.onerror
        throw new ValidationError('The username you entered is already in use.');
    });
}

我可以让checkUsernameAvailability接受回调和/或返回一个承诺,让它使用用户名的可用性执行所述回调。

$('#username').blur(function () {
    checkUsernameAvailability(username, function (available) {
        !available && alert('The username you entered is already in use.');
    });
});

但是,使异常如此强大的一部分原因是它们可以冒泡堆栈直到它们被捕获,而如果我有另一个函数调用另一个调用checkUsernameAvailability的函数,我需要通过这个回调的结果一直手动,直到我到达我想要处理它的地方。

将错误传递到堆栈的哪些替代方法有哪些?我可以想到其中一些,但没有一个像原生的例外一样干净:

  • 将标志或ValidationError实例传递给回调(Node.js方法也可以工作,传递错误或null作为第一个参数,数据作为第二个参数);但是,如果我不想在堆栈中的那一点处理它,我需要手动传递错误
  • 或者将2个回调传递给checkUsernameAvailability函数,成功回调和错误回调;这似乎与前一点有相同的缺点
  • 触发&#34; ValidationError&#34;事件,所以我可以在任何地方听,但请确保在处理程序中return false;,以便它不会在堆栈中执行更高;但是,这会污染事件命名空间,并且可能会使其不清楚首先执行哪个事件侦听器;此外,使用控制台
  • 很难将事件追溯到其原点

2 个答案:

答案 0 :(得分:0)

原则上就像这样

function Exception (errcode) {
  this.code = errcode;
}

...

try {
  ...
  throw new Exception('alpha');
  ...
} catch (e) {
  if (e.code === {something}) {
  }
}

答案 1 :(得分:0)

如果它有所帮助,我最近在C中为UNIX编写了第一个用于UNIX的Rogue游戏,并将其重写为javascript以在浏览器中工作。我使用了一种名为continuation的技术,能够等待用户输入密钥,因为在javascript中没有中断。

所以我会有一段这样的代码:

void function f() {

  // ... first part

  ch = getchar();

  // ... second part

}

将在

中转换
function f() {

  // ... first part

  var ch = getchar(f_cont1);

  return;
  // the execution stops here 

  function f_cont1 () {

    // ... second part
  }
}

然后存储继续以在keypressed事件上重用。有了闭包,一切都会在停止的地方重新启动。