2013-04-09 11 views
5

私は、AppleにverifyReceiptsと話すアプリを書いています。彼らはあなたが投稿できるサンドボックスとプロダクションの両方のURLを持っています。ネストされた約束できれいなコードを書く

21007のステータスを受け取った場合は、Appleと通信するとき、サンドボックスに投稿する必要があるときにプロダクションURLに投稿したことを意味します。

私はリトライロジックを容易にするためのコードを書きました。ここに私のコードの簡易版です。

var request = require('request') 
    , Q = require('q') 
    ; 

var postToService = function(data, url) { 
    var deferred = Q.defer(); 
    var options = { 
    data: data, 
    url: url 
    }; 

    request.post(options, function(err, response, body) { 
    if (err) { 
     deferred.reject(err); 
    } else if (hasErrors(response)) { 
     deferred.reject(response); 
    } else { 
     deferred.resolve(body); 
    } 
    }); 

    return deferred.promise; 
}; 

exports.verify = function(data) { 
    var deferred = Q.defer(); 

    postToService(data, "https://production-url.com") 
    .then(function(body) { 
     deferred.resolve(body); 
    }) 
    .fail(function(err) { 
     if (err.code === 21007) { 
     postToService(data, "https://sandbox-url.com") 
      .then(function(body){ 
      deferred.resolve(body); 
      }) 
      .fail(function(err) { 
      deferred.reject(err); 
      }); 
     } else { 
     deferred.reject(err); 
     } 

    }); 

    return deferred.promise; 
}; 

を確認する機能でリトライ部分は、ネストされた約束を読んでかなり醜いと困難です。これを行うより良い方法はありますか?

+0

ひとつのアイデアは、(/待ってC#の非同期に類似)継続渡しのための構文をサポートしているアイスのCoffeeScriptを使用しています:http://maxtaco.github.io/coffee-script /。残念なことに、これはCoffeeScriptとそれをサポートしていない "非標準的な"変種を使用する必要があります。 – millimoose

答えて

5

あなたは約束を拒否し続けることを拒否ハンドラでエラーを再スローすることもできますし、拒絶反応を置き換えるために新しい約束を返すことができます。

exports.verify = function(data) { 
    return postToService(data, "https://production-url.com") 
    .fail(function(err) { 
     if (err.code === 21007) { 
     return postToService(data, "https://sandbox-url.com") 
     } else { 
     throw err 
     } 
    }); 
}; 
+0

私はこれが好きです。ニース、きれいでシンプル! – Anton

0

次のようなものが考えられます。空白を賢明に使うことは読みやすさを助けることができると私は思う。あなたはおそらく、あなたのチームが良い気分になり、それに固執する合理的なスタイルの標準を見つけたいと思うでしょう!

exports.verify = function(data) { 
    var deferred = Q.defer(); 

    postToService(data, "https://production-url.com") 

    .then(deferred.resolve, function(err) { 

     if (err.code === 21007) { 

     postToService(data, "https://sandbox-url.com") 

      .then(deferred.resolve, deferred.reject); 

     } else { deferred.reject(err); } 

    }); 

return deferred.promise; 
}; 
1

ここにいくつかの可能性があります。この質問には個人的な趣味の要素があるので、あなたが見るものが好きかもしれません。

入場料 - 私はこのコードをテストしていない)

オプション1 - resolverejectのためのラッパーを使用してください。これは、ヘルパー関数の形で「ノイズ」を追加しますが、残りの部分は整理します。

var resolve = function (deferred, ob) { 
    return function() { 
    deferred.resolve(ob); 
    }; 
}; 

var reject = function (deferred, ob) { 
    return function() { 
    deferred.reject(ob); 
    }; 
}; 

exports.verify = function(data) { 
    var deferred = Q.defer(); 

    postToService(data, "https://production-url.com") 
    .then(resolve(deferred, body)) 
    .fail(function(err) { 
     if (err.code === 21007) { 
     postToService(data, "https://sandbox-url.com") 
      .then(resolve(deferred, body)) 
      .fail(reject(deferred, err)); 
     } else { 
     deferred.reject(err); 
     } 
    }); 

    return deferred.promise; 
}; 

オプション2 - バインドを使用します。これには既存のJS機能を使用する利点がありますが、コールバックの作成時にdeferredへの参照が重複しています。

exports.verify = function(data) { 
    var deferred = Q.defer(); 

    postToService(data, "https://production-url.com") 
    .then(deferred.resolve.bind(deferred, body)) 
    .fail(function(err) { 
     if (err.code === 21007) { 
     postToService(data, "https://sandbox-url.com") 
      .then(deferred.resolve.bind(deferred, body)) 
      .fail(deferred.reject.bind(deferred, err)); 
     } else { 
     deferred.reject(err); 
     } 
    }); 

    return deferred.promise; 
}; 

オプション3 - バインドと 'メソッドハンドル'(#2のマイナーバリエーション)を使用します。

exports.verify = function(data) { 
    var deferred = Q.defer(); 
    var resolve = deferred.resolve; 
    var reject = deferred.reject; 

    postToService(data, "https://production-url.com") 
    .then(resolve.bind(deferred, body)) 
    .fail(function(err) { 
     if (err.code === 21007) { 
     postToService(data, "https://sandbox-url.com") 
      .then(resolve.bind(deferred, body)) 
      .fail(reject.bind(deferred, err)); 
     } else { 
     deferred.reject(err); 
     } 
    }); 

    return deferred.promise; 
}; 

オプション4 - Monkey patch deferred。

function patch(deferred) { 
    deferred.resolveFn = function (ob) { 
    return function() { 
     deferred.resolve(ob); 
    }; 
    }; 
    deferred.rejectFn = function (ob) { 
    return function() { 
     deferred.reject(ob); 
    }; 
    }; 
    return deferred; 
} 

exports.verify = function(data) { 
    var deferred = patch(Q.defer()); 

    postToService(data, "https://production-url.com") 
    .then(deferred.resolveFn(body)) 
    .fail(function(err) { 
     if (err.code === 21007) { 
     postToService(data, "https://sandbox-url.com") 
      .then(deferred.resolveFn(body)) 
      .fail(deferred.rejectFn(err)); 
     } else { 
     deferred.reject(err); 
     } 
    }); 

    return deferred.promise; 
}; 
0

スチュアートの答えが正しい、というのはチェーンの約束だった。ラッピングのためにQ.deferを使用する必要はないことを明確にしたいと思います。それはアンチパターンとも考えられています。ここの理由を参照してくださいThe Deferred anti-pattern頭に浮かぶ

var request = require('request') 
    , Q = require('q'); 

var PRODUCTION_URL = "https://production-url.com", 
var SANDBOX_URL = "https://sandbox-url.com", 


export.verify = function() { 

    return postToProduction(data) 
     .fail(function(error) { 
      if (error.code === 21007) return postToSanbox(data); 
      throw error; 
     }); 
} 

function postToProduction(data) { 
    return postToService(data, PRODUCTION_URL); 
} 

function postToSandbox(data) { 
    return postToService(data, SANDBOX_URL); 
} 

function postToService(data, url) { 
    var deferred = Q.defer(); 

    var options = { 
     data: data, 
     url: url 
    }; 

    request.post(options, function(err, response, body) { 
    if (err) return deferred.reject(err); 
    if (hasErrors(response)) return deferred.reject(response); 

    deferred.resolve(body);  
    }); 

    return deferred.promise; 
} 
+0

'' Q.ninvoke'(とconsorts)を使って遅延を完全に避けることができます。 – Bergi

関連する問題