处理Meteor.Error和.wrapAsync() - 最好的方法?

时间:2015-07-08 02:24:53

标签: meteor

请批评以下处理Meteor错误的方法:

Meteor上Meteor.wrapAsync()方法的一个常见问题是它似乎没有从外部API返回实际错误:

https://github.com/meteor/meteor/issues/2774

1。使用wrapAsync()

的示例

我正在使用一个简单的API来获取美国邮政编码并返回位置信息:

/server/methods.js

var getLocationAsync = function(zipcode, callback){

  HTTP.call("GET", "http://api.zippopotam.us/us/" + zipcode, function(error, result) {
    callback(error,result);
  });

};

var getLocationWithWrap = Meteor.wrapAsync(getLocationAsync);

Meteor.methods({
    getLocationWithWrap: function(zipcode){
        return getLocationWithWrap(zipcode);
    }
});

如果你这样做

Meteor.call("getLocationWithWrap", "94043", function(error, result){
    if(error){
        console.log("here is the error: ", error)
    } else {
        console.log("success: ", result);
    }
})

你得到了适当的回应。但如果您传入无效的邮政编码:

Meteor.call("getLocationWithWrap", "940", function(error, result){
    if(error){
        console.log("here is the error: ", error)
    } else {
        console.log("success: ", result);
    }
})

你只得到一个没有意义的通用Internal server error [500]

2。使用try / catch的示例(请参阅代码注释)

Meteor.methods({
    getLocationWithWrapTryCatch: function(zipcode){
        try {
          return getLocationWithWrap(zipcode);
        } catch(error){
          // the error object just contains a 'stack' key 
          // and the value is difficult to use
          // but the error is a 404 rather than a 500
          throw new Meteor.Error(error.stack);
        }
    }
});

这样做的:

Meteor.call("getLocationWithWrapTryCatch", "940", function(error, result){
    if(error){
        console.log("here is the error: ", error)
    } else {
        console.log("success: ", result);
    }
})

会导致难以解析的错误对象。

第3。使用@faceyspacey代码的示例

用户@faceyspacey编写了一个他称为makeAsync的函数(我已将名称更改为makeSync,因为他的代码采用异步函数并允许您以同步方式编写)。 / p>

它的作用是返回一个对象:

{error:  error, data: data}

error的值是外部API返回的实际错误。如果error的值为null,则data的值将是外部API返回的数据。

/server/methods.js

Meteor.makeSync = function(fn, context) {
  return function (/* arguments */) {
    var self = context || this;
    var newArgs = _.toArray(arguments);
    var callback;

    for (var i = newArgs.length - 1; i >= 0; --i) {
      var arg = newArgs[i];
      var type = typeof arg;
      if (type !== "undefined") {
        if (type === "function") {
          callback = arg;
        }
        break;
      }
    }

    if(!callback) {
      var fut = new Future();
            callback = function(error, data) {
               fut.return({error:  error, data: data});
            };

      ++i; 
    }

    newArgs[i] = Meteor.bindEnvironment(callback);
    var result = fn.apply(self, newArgs);
    return fut ? fut.wait() : result;
  };
};

var getLocationAsync = function(zipcode, callback){

  HTTP.call("GET", "http://api.zippopotam.us/us/" + zipcode, function(error, result) {
    callback(error,result);
  });

};

var getLocationWithMakeSync = Meteor.makeSync(getLocationAsync);

Meteor.methods({
    getLocationWithMakeSync: function(zipcode){
        var result = getLocationWithMakeSync(zipcode);
        if( result.error === null ){
            return result.data;
        } else {
            throw new Meteor.Error(result.error.response.statusCode, "Zipcode cannot be found.");
        }
    },
});

现在你做的时候

Meteor.call("getLocationWithWrap", "94043", function(error, result){
    if(error){
        console.log("here is the error: ", error)
    } else {
        console.log("success: ", result);
    }
});

您将获得从外部API返回的实际错误或无错结果。

我个人更喜欢第三种方法,因为您可以从外部API中使用实际的错误对象。我在这里错过了什么吗?使用外部API时是否有更好的方法来处理异步错误?

2 个答案:

答案 0 :(得分:1)

@ faceyspacey的做法是我认为最好的方式。如果你看一下wrapAsync的源代码,它就非常相似(https://github.com/meteor/meteor/blob/832e6fe44f3635cae060415d6150c0105f2bf0f6/packages/meteor/helpers.js#L90)。该方法也用于几个外部包中。

答案 1 :(得分:1)

我来到这里遇到同样的麻烦:抛出的错误包含堆栈跟踪而不是原始错误。事实证明,原始错误被用作包含堆栈跟踪的对象的原型,但是:

https://github.com/meteor/meteor/issues/2774#issuecomment-70710564

  

......所有预期的属性都在那里,但它们都在   错误对象的原型而不是对象本身。查看   这个,在catch中添加for (var key in e) { console.log(e, e[key]); }   块。

我测试了它,当然,它确实有效。