4

作为 Javascript 的新手,我很困惑哪个可能是区分异步函数计算的结果和任何异常/错误的最佳方法。如果我是对的,你不能在这种情况下使用 try-catch,因为被调用的函数在回调之前结束,而后者实际上可能会抛出异常。

好。

到目前为止,我已经看到一些库函数需要回调,例如function(err, result):因此,err使用前必须进行测试result

我还尝试自己返回实际结果或错误对象。在这里,回调是形式的function(result) ,您必须 result instanceof Error在使用它之前进行测试。它遵循一个例子:

function myAsyncFunction ( callBack ) {

 async_library_function( "some data", function (err, result) {
         if (err) {  callBack ( new Error ("my function failed") ); return; }

         callBack ( some calculation with result );        
 });

} // myFunction ()

//
// calling myFunction
//
myAsyncFunction (    function (result) {
    if (result instanceof Error ) { log ("some error occurred"); return; }

   log ("Alright, this is the result: " + result);
});

最好的(也许是常见的)方法是什么?

谢谢。

4

5 回答 5

1

这在很大程度上取决于您的实施。这是可恢复的错误吗?如果不是,那么您建议的方式应该可以正常工作。如果它是可恢复的,那么您不应该返回错误。你应该返回一个“空”的结果。还要记住可维护性。你想在整个代码中检查 instanceof 吗?另外,我知道一些程序员喜欢 JavaScript 的类型很松散,但是当预期的对象传递实际上可能是意外时,你会遇到一致性问题。这是一个结果,还是一个错误,甚至完全是别的什么?

于 2013-10-17T15:38:53.327 回答
1

这是一种方法。虽然我通常会将结果的任何操作/处理留给回调函数。

另一种方法是您可以将错误和结果值都传回回调:

callback (err, result); \\ if no error, err = null, if no result, result = null

或者,您可以要求单独的错误和成功回调:

function myAsyncFunction ( successCallBack, errorCallBack ) {
    \* ... *\
 }

然后根据收到的响应触发相应的函数。

于 2013-10-17T15:39:09.320 回答
1

一种方法可以是这样的:

function Exception(errorMessage)
{
    this.ErrorMessage = errorMessage;

    this.GetMessage = function()
    {
        return this.ErrorMessage;
    }
}

function ResultModel(value, exception)
{
    exception = typeof exception == "undefined"? null, exception;

    this.Value = value;
    this.Exception = exception;

    this.GetResult = function()
    {
        if(exception === null)
        {
            return this.Value;
        }
        else
        {
             throw this.Exception;
        }
    }
};

在您的使用中:

function myAsyncFunction ( callBack ) {

    var result;

    async_library_function( "some data", function (err, result) {

         if (err) 
         {  
             result = new ResultModel(null, new Exception("my function failed"));
         }
         else
         {
             result = new ResultModel(some calculation with result);
         }

         callBack ( result );        
 });

} 

myAsyncFunction (    function (result) {

    try
    {
        log ("Alright, this is the result: " + result.GetResult());
    }
    catch(ex)
    {
        log ("some error occurred" + ex.GetMessage()); 
        return;
    }
});
于 2013-10-17T15:41:00.897 回答
1

我自己一直在使用三种主要方法:

  1. 将“错误”参数传递给回调。
  2. 有一个“错误”回调。这通常与(1)结合使用。
  3. 拥有某种全局异常管理器。

我将从第三个开始。这个想法是有一个对象,它将允许分派错误以及全局捕获它们。像这样的东西:

var ErrorManager = {
  subscribers: [],

  subscribe: function (callback) { 
    this.subscribers.push(callback); 
  },

  dispatchError: function (error) {
    this.subscribers.forEach(function (s) {
      s.apply(window, [ error ]);
    });
  }
}

这对于给定的情况是非常具体的,因为基本上没有简单的方法来跟踪错误的起源,而且很容易搞砸这一点。例如,如果您需要隐藏内容加载失败的对话框,则必须将此信息(例如对话框 ID/元素)传播给所有订阅者。

当您想要执行不改变(或改变独立部分)Web 应用程序的操作(例如,向控制台显示状态栏或消息)时,上述方法非常有用

第二种方法基本上将成功调用和失败分开。例如:

$.ajax('/articles', {
  success: function () { /* All is good - populating article list */ },
  error: function () { /* An error occured */ }
});

在上面的例子中,success回调永远不会在失败的情况下执行,所以如果你想让一些默认行为总是触发,你需要在两个回调之间同步或者有一个总是被调用的回调(对于上面的例子 - complete)。

我个人更喜欢第一种方法 - 有一个回调,你有一个错误对象与潜在结果一起传递。这消除了必须“跟踪”错误的来源/上下文以及担心清理过程(默认行为)的问题。所以,像你提供的东西:

function beginFetchArticles(onComplete) {
  $.ajax('/articles', {
    complete: function (xhr) {
      onComplete(xhr.status != 200 ? xhr.status.toString() : null, 
        $.parseJSON(xhr.responseText)); /* Something a bit more secure, probably */
    }
  });
}

希望这可以帮助。

于 2013-10-17T15:51:31.513 回答
1

如果你想制作健壮的程序,你应该使用 Promise。否则你必须处理 2 种不同类型的错误,这很疯狂。

考虑如何在不使服务器崩溃的情况下以 JSON 格式读取文件:

var fs = require("fs");

fs.readFile("myfile.json", function(err, contents) {
    if( err ) {
        console.error("Cannot read file");
    }
    else {
        try {
            var result = JSON.parse(contents);
            console.log(result); //Or continue callback hell here
        }
        catch(e) {
            console.error("Invalid json");
        }
    }

});

承诺例如:

var Promise = require("bluebird");
var readFile = Promise.promisify(require("fs").readFile);

readFile("myfile.json").then(JSON.parse).then(function(result){
    console.log(result);
}).catch(SyntaxError, function(e){
    console.error("Invalid json");
}).catch(function(e){
    console.error("Cannot read file");
});

还要注意代码是如何像同步代码一样垂直增长而不是水平增长的。

于 2013-10-17T19:00:42.520 回答