Jaka jest wyraźna obietnica konstrukcji przeciwwzorcowej i jak jej uniknąć?

May 22 2014

Pisałem kod, który robi coś takiego:

function getStuffDone(param) {           | function getStuffDone(param) {
    var d = Q.defer(); /* or $q.defer */ |     return new Promise(function(resolve, reject) {
    // or = new $.Deferred() etc.        |     // using a promise constructor
    myPromiseFn(param+1)                 |         myPromiseFn(param+1)
    .then(function(val) { /* or .done */ |         .then(function(val) {
        d.resolve(val);                  |             resolve(val);
    }).catch(function(err) { /* .fail */ |         }).catch(function(err) {
        d.reject(err);                   |             reject(err);
    });                                  |         });
    return d.promise; /* or promise() */ |     });
}                                        | }

Ktoś mi powiedział, że nazywa się to odpowiednio „ odroczonym antywzorem ” lub „ Promiseantywzorem konstruktora ”. Co jest złego w tym kodzie i dlaczego nazywa się to antywzorem ?

Odpowiedzi

380 BenjaminGruenbaum May 22 2014 at 17:07

Odroczone antywzorzec projektowy (obecnie wyraźne-budowa antywzorzec projektowy) wymyślone przez Esailija jest wspólne antywzorzec projektowy ludzi, którzy są nowicjuszami w obietnice zrobić, zrobiłem to sam, kiedy po raz pierwszy użyty obietnic. Problem z powyższym kodem polega na tym, że nie wykorzystuje faktu, że łańcuch obiecuje.

Obietnice można łączyć z obietnicami .theni można je bezpośrednio zwracać. Twój kod w getStuffDonemożna przepisać jako:

function getStuffDone(param){
    return myPromiseFn(param+1); // much nicer, right?
}

Obietnice dotyczą zwiększenia czytelności kodu asynchronicznego i zachowania się jak kod synchroniczny bez ukrywania tego faktu. Obietnice reprezentują abstrakcję wartości jednorazowej operacji, abstrakcję stanowią pojęcie instrukcji lub wyrażenia w języku programowania.

Odroczonych obiektów należy używać tylko wtedy, gdy konwertujesz interfejs API na obietnice i nie możesz tego zrobić automatycznie, lub gdy piszesz funkcje agregacji, które można łatwiej wyrazić w ten sposób.

Cytując Esailija:

Jest to najczęstszy anty-wzór. Łatwo się w to wpaść, gdy tak naprawdę nie rozumiesz obietnic i myślisz o nich jako o chwalebnych emiterach zdarzeń lub narzędziu wywołania zwrotnego. Podsumujmy: obietnice dotyczą zachowania większości utraconych właściwości kodu synchronicznego w kodzie asynchronicznym, takich jak płaskie wcięcia i jeden kanał wyjątków.

142 Bergi Aug 29 2014 at 20:28

Co jest z tym nie tak?

Ale wzór działa!

Szczęściarz. Niestety, prawdopodobnie tak nie jest, ponieważ prawdopodobnie zapomniałeś o jakimś skrajnym przypadku. W ponad połowie przypadków, które widziałem, autor zapomniał zająć się obsługą błędów:

return new Promise(function(resolve) {
    getOtherPromise().then(function(result) {
        resolve(result.property.example);
    });
})

Jeśli druga obietnica zostanie odrzucona, stanie się to niezauważone, a nie zostanie przekazane do nowej obietnicy (gdzie zostanie zrealizowana) - a nowa obietnica pozostaje na zawsze w toku, co może powodować przecieki.

To samo dzieje się w przypadku, gdy Twój kod wywołania zwrotnego powoduje błąd - np. Gdy resultnie ma a propertyi zostanie zgłoszony wyjątek. To byłoby nierozwiązane i pozostawiłoby nową obietnicę nierozwiązaną.

W przeciwieństwie do tego, używanie .then()automatycznie obsługuje oba te scenariusze i odrzuca nową obietnicę, gdy wystąpi błąd:

 return getOtherPromise().then(function(result) {
     return result.property.example;
 })

Odroczony antywzór jest nie tylko uciążliwy, ale także podatny na błędy . Używanie .then()do łączenia jest znacznie bezpieczniejsze.

Ale ja załatwiłem wszystko!

Naprawdę? Dobry. Jednak będzie to dość szczegółowe i obszerne, zwłaszcza jeśli używasz biblioteki obietnic, która obsługuje inne funkcje, takie jak anulowanie lub przekazywanie wiadomości. A może w przyszłości tak się stanie, a może chcesz zamienić swoją bibliotekę na lepszą? Nie będziesz chciał przepisać w tym celu swojego kodu.

Metody bibliotek ( then) nie tylko natywnie obsługują wszystkie funkcje, ale mogą również mieć pewne optymalizacje. Korzystanie z nich prawdopodobnie przyspieszy kod lub przynajmniej pozwoli na jego optymalizację przez przyszłe wersje biblioteki.

Jak tego uniknąć?

Jeśli więc zauważysz, że ręcznie tworzysz obietnice Promiselub Deferredi masz już istniejące obietnice, najpierw sprawdź interfejs API biblioteki . Odroczony antywzór jest często stosowany przez ludzi, którzy postrzegają obietnice [tylko] jako wzorzec obserwatora - ale obietnice to coś więcej niż wywołania zwrotne : mają być kompozycyjne. Każda przyzwoita biblioteka ma wiele łatwych w użyciu funkcji do komponowania obietnic w każdy możliwy do wyobrażenia sposób, zajmujących się wszystkimi niskopoziomowymi rzeczami, którymi nie chcesz się zajmować.

Jeśli zauważyłeś potrzebę skomponowania niektórych obietnic w nowy sposób, który nie jest obsługiwany przez istniejącą funkcję pomocniczą, napisanie własnej funkcji z nieuniknionymi Odroczeniami powinno być ostatnią opcją. Rozważ przejście na bardziej funkcjonalną bibliotekę i / lub zgłoś błąd w swojej obecnej bibliotece. Jego opiekun powinien być w stanie wyprowadzić kompozycję z istniejących funkcji, zaimplementować nową funkcję pomocniczą i / lub pomóc zidentyfikować przypadki skrajne, które należy obsłużyć.