2016-09-26 6 views
0

私は約束を使って別のライブラリにコールを連鎖したいと思っています。エラーが発生した場合、ライブラリメソッドはエラーを記述するオブジェクトを返しますが、ライブラリに応じてフィールドが異なります。プロミスチェーンのエラーオブジェクトを正規化する方法は?

被呼び出し者に一貫してエラーを報告するには、すべてのエラーオブジェクトを共通形式に正規化します。しかし、私はBluebirdや標準的な約束APIを使ってうまくいく方法を知らない。ここでは、擬似JSで

は私が持っているものです。

var methodAFromLibX_Async = Promise.promisify(...); 
var methodBFromLibY_Async = Promise.promisify(...); 

methodAFromLibX_Async(...) 
.then(function(result) { 
    methodBFromLibY_Async(...) 
    .then(function(result) { ... }) 
    .catch(normalizeAndSendErrorFromLibY); 
}) 
.catch(normalizeAndSendErrorFromLibX); 

上記のコードが仕事にだが、:

  1. 私はnormalizeAndSendErrorFromLibYnormalizeAndSendErrorFromLibX
  2. 間の冗長なコードを持っているI私の実際の使用例私は2つ以上の呼び出しをチェーンしなければならず、コードのピラミッド形は間違いなくコールバック地獄のように見え始めます。

EDIT:、もう少し明確にするために、ここで私が想像するが、達成することはできません解決策: chain with parallel path for errors & ok results

+1

すると、あなたはすべての可能なエラーを正常化するあなたのチェーンの最後に単一 'catch'を持っているし、それらを「送信」することはできません何らかの理由があります? – m90

+0

コメントありがとうございました@ m90。最後にはグローバルな 'catch' /' catchAll'だけで、エラーの起源についての知識は失われています。私の例で説明したように、さまざまなlib呼び出しからエラーが発生した場合、 'if..else'ブロックの束を使って、私は元を推測することができます。しかし、チェーン内で同じlibのメソッドをいくつか呼び出すと、トレースを戻すのがより複雑になります。私はもっ​​と優雅なやり方がないと信じられません。 –

+0

あなたはあなたが望む鎖ですか? 'normErrorFromY'は' normErrorFromX'のエラーを処理しますか? – Bergi

答えて

1

+0

['Promise.coroutine'](http://bluebirdjs.com/docs/api/promise.coroutine.html)とジェネレータを使って' methodA、B& '.then()'で連鎖するのではなく、 'C'を使用します。私はそれを[代替ソリューション](http://stackoverflow.com/a/39701754/2363712)として投稿しましたが、 '.catch'ハンドラがエラーを処理するとは思っていません。 –

+1

'reportSuccess'が最後のものだけでなく、すべての結果を必要とするなら、それは完全にうまくいっています[良い解決法](http://stackoverflow.com/a/28250697/1048572)。 'catch'は期待通りに動作します。あるいはジェネレータ関数のコードの周りに' try'/'catch'を置くこともできます。 – Bergi

+0

確認していただきありがとうございます。私はここで中間結果を必要とする必要はありませんが、私はツールボックスにそのオプションを保持します! –

1

あなたがで実証されているパターンを回避したい場合あなたの例はあなたのために2つの他のオプションがあるようです:

あなたのライブラリは、図のようにあなたのライブラリを正しく伝播し、正規化できる1つの関数を構築しますすべての既知のエラー:

var methodAFromLibX_Async = Promise.promisify(...); 
var methodBFromLibY_Async = Promise.promisify(...); 

methodAFromLibX_Async(...) 
.then(function(result) { 
    return methodBFromLibY_Async(...) 
    .then(function(result) { ... }) 
}) 
.catch(function(err){ 
    if (hasLibXShape(err)){ 
    return Promise.reject(normalizeLibXErr(err)); 
    } else if (hasLibYShape(err)){ 
    return Promise.reject(normalizeLibYErr(err)); 
    } 
}) 
.catch(function(normalizedErr){ 
    // handle normalized error 
}); 

他のオプションは、手動で、あなたのライブラリー方法をpromisify、ここでエラーを正常化するために、次のようになります。あなたの最新のコメントを読む

function promisifiedMethodA(/*...args*/){ 
    var args = [].slice.call(arguments); 
    return new Promise(function(resolve, reject){ 
     methodA.apply(null, args.concat([function(err, data){ 
      if (err) return reject(normalizeMethodAError(err)); 
      resolve(data); 
     }])); 
    }); 
} 

私は後者がより良いあなたのニーズに合うかもしれませんね。あなたが探しているソリューションは

return methodAFromLibX_Async(…) 
.then(function(result) { 
    return methodBFromLibY_Async(…) 
    .then(function(result) { 
      return methodCFromLibX_Async(…) 
      .catch(normalizeAndThrowErrorFromLibX); 
    }, normalizeAndThrowErrorFromLibY); 
}, normalizeAndThrowErrorFromLibX) 
.then(reportSuccess, reportError); 

である。しかし、これはかなりある

var methodAFromLibX_Async = Promise.promisify(...); 
var methodBFromLibY_Async = Promise.promisify(...); 

methodAFromLibX_Async(...) 
.then(function(result) { 
    return methodBFromLibY_Async(...); 
}).then(function(result) { 
    ... 
}).catch({code: 'X_Async', message: 'bad lib X'}, function(e) { 
    //If it is a methodAFromLibX_AsyncError, will end up here because 

}).catch({code: 'Y_Async', message: 'bad lib Y'}, function(e) { 
    //Will end up here if a was never declared at all 

}).catch(function(e) { 
    //Generic catch-the rest, error wasn't methodAFromLibX_AsyncError nor 
    //methodBFromLibY_AsyncError 
}); 
+1

確かに、私は手動で私のライブラリメソッドを約束し、そこでエラーを標準化することができました。ブルーバードの医師は、これがアンチパターンであると言って、私はその選択肢を考慮していないと主張しています。しかし今のところ、これは最高の解決策と思えます。 –

1

あなたは青い鳥フィルターキャッチ使用することができますhttp://bluebirdjs.com/docs/api/catch.html#filtered-catch

をそして、このような何かにあなたのコードを変更します醜い。とにかくエラーハンドラがエラーを再現するとすれば、まだ最適ではない、

return methodAFromLibX_Async(…) 
.catch(normalizeAndThrowErrorFromLibX) 
.then(function(result) { 
    return methodBFromLibY_Async(…) 
    .catch(normalizeAndThrowErrorFromLibY) 
    .then(function(result) { 
      return methodCFromLibX_Async(…) 
      .catch(normalizeAndThrowErrorFromLibX); 
    }); 
}) 
.then(reportSuccess, reportError); 

を使用することもできます。これらの関数を呼び出すたびに.catch(normalise)を入れたくないので、強制的に入れ子にする必要はありません。各自の機能をよりよく考慮する:

function withRejectionHandler(fn, normalise) { 
    return function() { 
     return fn.apply(this, arguments).catch(normalise); 
    }; 
} 
var methodA = withRejectionHandler(methodAFromLibX_Async, normalizeAndThrowErrorFromLibX); 
var methodB = withRejectionHandler(methodBFromLibY_Async, normalizeAndThrowErrorFromLibY); 
var methodA = withRejectionHandler(methodCFromLibX_Async, normalizeAndThrowErrorFromLibX); 

return methodA(…).then(methodB).then(methodC).then(reportSuccess, reportError); 

これをライブラリメソッドの約束と組み合わせることができます。代替策として

+0

ありがとうございますが、私のライブラリはエラーを普通のオブジェクトとして返します。エラーのインスタンスではなく、さらにエラーの特定の*サブクラス*からのものです。あなたはその場合でも解決策を働かせますか? catchAll節に共通コードを除外する方法はありますか? –

+0

コードやオブジェクトキーでフィルタリングを試すことができます。 'fs.readFileAsync(...) .then(...) .catch({code: 'ENOENT'}、function(e){ console.log("ファイルが見つかりません "+ e.path ); }); – Anouar

0

、ブルーバードのPromise.coroutineを使用して:

/* Bergi's solution to normalize */ 
function withRejectionHandler(fn, normalise) { 
    return function() { 
     return fn.apply(this, arguments).catch(normalise); 
    }; 
} 
var methodA = withRejectionHandler(methodAFromLibX_Async, normalizeAndThrowErrorFromLibX); 
var methodB = withRejectionHandler(methodBFromLibY_Async, normalizeAndThrowErrorFromLibY); 
var methodA = withRejectionHandler(methodCFromLibX_Async, normalizeAndThrowErrorFromLibX); 

/* use of coroutine to sequence the work */ 
var workflow = Promise.coroutine(function*() { 
    var resA = yield methodA(...); 
    var resB = yield methodB(...); 
    var resC = yield methodC(...); 

    reportSuccess(resA, resB, resC); 
}); 

workflow().catch(reportError); 
関連する問題