Что является явным обещанием строительной антипатрии и как мне избежать этого.

javascript promise q bluebird es6-promise


Я писал код,который делает что-то похожее:

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() */ |     });
}                                        | }

Кто-то сказал мне, что это называется « отложенным антипаттерном » или « антипаттерном конструктора Promise » соответственно, что плохого в этом коде и почему он называется антипаттерном ?





Answer 1 Benjamin Gruenbaum


Отложенный антипаттерн (в настоящее время анти-паттерн явной конструкции), придуманный Эсайлией, является распространенным анти-паттерном людей, которые плохо знакомы с обещаниями, я сделал это сам, когда впервые использовал обещания. Проблема с приведенным выше кодом заключается в том, что он не использует тот факт, что обещает цепочку.

Обещания могут .then с .then, и вы можете возвращать обещания напрямую. Ваш код в getStuffDone может быть переписан как:

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

Обещания заключаются в том,чтобы сделать асинхронный код более читабельным и вести себя как синхронный код,не скрывая этого факта.Обещания представляют собой абстракцию над значением одноразовой операции,они абстрагируют понятие оператора или выражения в языке программирования.

Вы должны использовать отложенные объекты только тогда, когда вы конвертируете API в обещания и не можете делать это автоматически, или когда вы пишете функции агрегации, которые проще выразить таким образом.

Цитирую Эсаилию:

Это самый распространенный анти-образец.В это легко попасть,если вы не понимаете обещаний и думаете о них,как о прославленных эмиттерах событий или утилитах обратного вызова.Резюмируя,обещания заключаются в том,чтобы заставить асинхронный код сохранить большую часть потерянных свойств синхронного кода,таких как плоский отступ и один канал исключений.




Answer 2 Bergi


Что с ним не так?

Но шаблон работает!

Повезло тебе.К сожалению,скорее всего,нет,так как ты,скорее всего,забыл какой-нибудь крайний случай.Более чем в половине случаев,которые я видел,автор забыл позаботиться об обработчике ошибок:

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

Если другое обещание будет отвергнуто,то это произойдет незамеченным,вместо того,чтобы быть переданным новому обещанию (где оно будет обработано)-и новое обещание останется в ожидании навсегда,что может привести к утечкам.

То же самое происходит в том случае, если ваш код обратного вызова вызывает ошибку - например, когда result не имеет property и генерируется исключение. Это было бы необработанным и оставило бы новое обещание нерешенным.

Напротив, использование .then() автоматически позаботится об обоих этих сценариях и отклонит новое обещание при возникновении ошибки:

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

Отложенный антипаттерн не только громоздок, но и подвержен ошибкам . Использование .then() для создания цепочек намного безопаснее.

Но я со всем разобрался!

Правда? Хорошо.Тем не менее,это будет довольно подробно и много,особенно если вы используете библиотеку обещаний,которая поддерживает другие функции,такие как отмена или передача сообщений.Или,может быть,это будет в будущем,или вы хотите поменять вашу библиотеку на лучшую? Вы не захотите переписывать свой код для этого.

Методы библиотек ( then ) не только изначально поддерживают все функции, они также могут иметь определенные оптимизации. Их использование, скорее всего, сделает ваш код быстрее или, по крайней мере, позволит оптимизировать будущие изменения библиотеки.

Как мне избежать этого?

Поэтому всякий раз, когда вы обнаруживаете, что создаете Promise или Deferred вручную, и уже задействованы уже существующие обещания, сначала проверьте библиотечный API . Отложенный антипаттерн часто применяется людьми, которые видят обещания [только] как образец наблюдателя - но обещания - это больше, чем обратные вызовы : они должны быть составными. Каждая приличная библиотека имеет множество простых в использовании функций для составления обещаний всеми возможными способами, заботясь обо всех вещах низкого уровня, с которыми вы не хотите иметь дело.

Если Вы нашли необходимость в составлении некоторых обещаний новым способом,который не поддерживается существующими вспомогательными функциями,то написание собственной функции с неизбежными деферредами должно быть Вашим последним вариантом.Подумайте о том,чтобы перейти на более функциональную библиотеку,а также или отправить ошибку против вашей текущей библиотеки.Ее сопровождающий должен быть в состоянии извлечь композицию из существующих функций,реализовать новую вспомогательную функцию для вас andor помочь определить крайние случаи,которые необходимо обработать.