4

私は Ember.js 内で配布されている RSVP ライブラリを使用しており、promise 内で致命的なエラーを報告するための正しいパターンを見つけようとしています。 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 を使用して、どこかからエラーが発生するようにするというアイデアに出くわしました

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 のデバッグを支援するために従うべき合理的なパターンのように思えますか?

4

2 に答える 2

2

新しい答え --

この ember コア開発者とのビデオ パネル ディスカッションでは、ある時点で開発者全員が 1 つのデバッグのヒントを共有しています。

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

Tom Dale は特に、promise 内の飲み込まれた例外の問題に対処し、新しい Ember.RSVP.onerror 機能を使用して、拒否ハンドラーがアタッチされていないために報告されなかった Promise 内のエラーをデバッグすることを推奨しています。

それが私の質問に対する正しい答えだと思います-RSVP.onerrorコールバックの使用方法(または使用可能なemberが解放される方法)はまだわかりません...

于 2013-08-01T00:25:17.363 に答える
0

いい質問です!

setTimeout開発環境内で回避できます。ただし、たとえばレポート用にこれらのエラーをログに記録する本番環境では、setTimeout非決定論的であるため回避する必要があります。実際には正確ではないエラーが発生する可能性がありますが、setTimeout起動した順序が原因で発生しました。

これを行うには、チェックをプロミスの最初に移動し、直接延期する代わりにthenそれを返します。thenable

Ember.Deferredの代わりに使用することを好みますEmber.RSVP.Promise。より優れた API を備えDeferredたレイヤーです。RSVPへのコールバック内にすべてをネストする必要がなくなります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 の任意の時点でエラーをスローすると、promise は自動的に拒否されます。したがって、何かをキャッチして再スローする必要はありません。

これにより、3 種類の応答が可能になります。

successCallback と応答データ。

 successCallback({data: 'foo'});

応答にエラーがある successCallback。

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

メッセージ付きの errorCallback。

 errorCallback('Incorrect use of API');

これを試すには、このjsbinを参照してください。

呼び出す API がコールバックの代わりに promise を使用する場合、これを少しきれいにすることができます。その後、チェーンすることができますthens

于 2013-07-26T05:56:35.023 に答える