2013-04-09 11 views
5

Piszę aplikację, która rozmawia z Apple w celu weryfikacjiReceipts. Mają zarówno piaskownicę, jak i URL do produkcji, do którego możesz publikować.Pisanie czystego kodu z zagnieżdżonymi obietnicami

Podczas komunikacji z Apple, jeśli otrzymujesz status 21007, oznacza to, że publikujesz na produkcyjnym adresie URL, kiedy powinieneś publikować w piaskownicy.

Napisałem więc kod, aby ułatwić logikę ponowną. Oto uproszczona wersja mojego kodu:

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; 
}; 

Część ponawiania w funkcji sprawdzenia jest dość brzydkie i trudne do odczytania z zagnieżdżonych obietnic. Czy jest lepszy sposób na zrobienie tego?

+0

Jednym z pomysłów, które przychodzi do głowy jest użycie Iced coffeescript który posiada wsparcie dla składniowej kontynuacją przejściu (podobny do C# 's async/czekają): http://maxtaco.github.io/coffee-script /. Niestety wymagałoby to użycia CoffeeScript i jego "niestandardowego" wariantu, który nie jest obsługiwany przez pomruk i tym podobne. – millimoose

Odpowiedz

5

Możesz ponownie rzucać błąd w module obsługi odrzucenia kontynuować odrzucając obietnicę, czy można powrócić nową obietnicę zastąpienia odrzucenia.

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

Podoba mi się to. Ładne, czyste i proste! – Anton

0

Możesz rozważyć coś takiego. Myślę, że rozsądne wykorzystanie białych znaków może pomóc w czytelności. Prawdopodobnie zechcesz znaleźć rozsądny standard stylu, z którym Twoi członkowie zespołu dobrze się czują i trzymają się go!

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

Oto kilka możliwości. Ponieważ to pytanie ma element osobistego smaku, możesz lub nie lubisz tego, co widzisz!

(Wstęp - Nie zostały przetestowane kod)

Wariant 1 - używać opakowującym resolve i reject. Dodaje to "szumu" w postaci funkcji pomocnika, ale upraszcza resztę.

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; 
}; 

Opcja 2 - Użyj wiązania. Ma to tę zaletę, że wykorzystuje istniejącą funkcjonalność JS, ale podczas tworzenia wywołań zwrotnych występują powielone odniesienia do 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; 
}; 

Opcja 3 - Użyj wiązania i "uchwytów metod" (zmiana niewielka na # 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; 
}; 

Opcja 4 - Odłóż małpkę odroczoną.

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

Odpowiedź Stuarta jest słuszna, chodziło o obietnice łańcuchowe. i chciałbym wyjaśnić, że nie jest konieczne używanie Q.defer tylko do zawijania. jest nawet uważany za anty-wzór. Zobacz powody tutaj 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

Można całkowicie uniknąć opóźnień przy użyciu 'Q.ninvoke' (i konsorcjów) – Bergi

Powiązane problemy