“LOUD”错误的可接受承诺模式?

时间:2013-07-25 19:06:33

标签: javascript ember.js promise rsvp.js

我正在使用在Ember.js中分发的RSVP库,我正在试图找出在承诺中报告致命错误的正确模式 - 特别是我想告知一些几乎可以肯定是编程结果的东西由于api误用导致的错误,我想以LOUD方式进行。我一般都是承诺和javascript的新手,希望这个问题有意义

这是一个简单的例子(在coffeescript中):

doAsync = (arg, callback) ->
  throw new Error('you gave me a way bad arg, I fail for you!')

promiseReturningApi = (data) ->
  return new Ember.RSVP.Promise (resolve, reject) ->
    callback = (err, resp) ->
      if err then reject(err)
      else resolve(resp)
    doAsync(data, callback)

现在让我说我已经确定了一个错误,即没有可能从doAsync中发生的恢复方法 - 我想确保报告此错误,即使调用者忽略了附加错误处理程序,因为它几乎肯定只是结果是因为调用者以不正确的方式调用了api函数

我遇到了在拒绝处理程序中使用setTimeout以确保从某处引发错误的想法,即使调用者没有将错误处理程序附加到promise

failLoud = (err) ->
  if err.isProgrammerError
    setTimeout () ->
      throw err
  throw err

promiseReturningApi = (data) ->
  promise = new Ember.RSVP.Promise (resolve, reject) ->
    callback = (err, resp) ->
      if(err) then reject(err)
      else resolve(resp)
    doAsync(data, callback)
  return promise.then(null, failLoud)

在从promiseReturningApi返回之前,将这样的默认错误处理程序附加到承诺是否合理?这将允许我在调用者执行无法工作的事情时强制执行堆栈跟踪 - 即使堆栈跟踪有点奇怪,它可以使事情更容易开始......

即使我调用了示例promise将函数返回'api'调用 - 我应该补充一点,我不是在编写框架代码 - 这完全在一个应用程序中。如果doAsync是一个真实世界的功能,那么在我的现实世界中它很可能来自一个带有新到我的api的外部派对 - 所以我很可能会误用它而我已经开始了解它...意思是我可能想要制作类似这样的模式

failLoud = (err) ->
  if err?.isProgrammerError
    setTimeout () ->
      throw err
  throw err

promiseReturningApi = (data) ->
  promise = new Ember.RSVP.Promise (resolve, reject) ->
    callback = (err, resp) ->
      if(err) reject(err)
      resolve(resp)
    try
      doAsync(data, callback)
    catch err
      err.isProgrammerError = true
      throw err
   return promise.then(null, failLoud)

我认为这样做是在我的异步函数调用本身引发异常的任何时候强制从某处抛出异常 - 这种异常几乎肯定会在参数期间引发异步调用的验证阶段,这通常是我的应用程序代码传递给没有任何意义的东西的结果 - 我想尽快找到它。在这种情况下,这似乎是一个合理的模式,可以帮助调试应用程序代码中使用的promise吗?

2 个答案:

答案 0 :(得分:2)

新答案 -

在与ember核心开发人员的视频小组讨论中,开发人员一度共享一个调试提示:

http://www.youtube.com/watch?v=L9OOMygo1HI

Tom Dale专门解决了承诺中的吞没异常问题,并建议使用新的Ember.RSVP.onerror功能来调试promises中的错误,否则这些错误将因为没有附加拒绝处理程序而未报告。

我认为这是我的问题的正确答案 - 虽然我还不知道如何使用RSVP.onerror回调(或者其中ember发布其可用的)...

答案 1 :(得分:0)

好问题!

您可以在开发环境中使用setTimeout。但是对于生产中您记录这些错误以进行报告的情况,您需要避免使用setTimeout,因为它不确定。您最终可能会看到不准确的错误,但是由于setTimeout被解雇的某个顺序而发生。

您可以将支票移至承诺的第一个then,然后返回thenable而不是直接延期。

我更喜欢使用Ember.Deferred代替Ember.RSVP.PromiseDeferredRSVP之上的一个层,它具有更好的API。它避免了将整个事物嵌套到Ember.RSVP.Promise的回调中。 Ember.Deferred提供了resolvereject作为方法。

model: function(params) {
  var promise = Ember.Deferred.create();
  var successCallback = function(resp) {
    promise.resolve(resp);
  };

  var errorCallback = function(err) {
    promise.reject(err);
  };

  var thenable = promise.then(function(resp) {
    if (resp.isError) {
      throw new Error(resp.errorMessage);
    } else {
      return resp;
    }
  });

  // some api that takes a callback
  this.callApi(params, successCallback, errorCallback);

  return thenable;
},

在promise / API中的任何一点抛出错误都会自动拒绝承诺。所以你不需要捕捉和重新抛出任何东西。

这允许3种不同类型的回复。

带响应数据的successCallback。

 successCallback({data: 'foo'});

successCallback,响应错误。

 successCallback({isError: true, errorMessage: 'Response data is wrong'});

errorCallback with message。

 errorCallback('Incorrect use of API');

请参阅此jsbin进行试用。

如果您调用的API使用promises而不是回调,则可以稍微清理一下。然后你可以链接thens