Сохранение читаемых цепочек
Я привык обещать цепочки массивов. Невероятно легко читать цепочку обещаний, когда каждое обещание длинное, например
myArray.map(x => convertX)
.filter()
.whatever()
.etc()
Это невероятно легко читать. Однако, когда я создаю цепочки обещаний с пользовательскими функциями, он становится намного более беспорядочным.
database.query(first query)
.then(results => {
// do stuff
// do more
// even more
return database.query(second query)
})
.then(results => {
// rinse and repeat
})
.catch(err => {
// error handling
})
Теперь это может быть разборчивым, но когда цепочка обещаний распространяется дальше, она становится немного. Если я сделаю каждое обещание своей собственной функцией, тогда я могу оптимизировать процесс, чтобы код выглядел примерно так (что imo, на 1000 раз больше разборчиво).
db.query(first query)
.then(storeFirstQuery)
.then(secondQueryAndStoreIt)
.then(thirdQueryAndStoreIt)
.catch(errHandlingFunction)
Таким образом, я могу изменить функции без необходимости манипулировать значениями, которые передаются от одного обещания к следующему. Если обещание использует результат другого, оно должно быть только после другого, но не сразу после. Таким образом я могу прокрасться promises туда, где мне нужно.
Однако для этого требуется, чтобы моя цепочка обещаний использовала переменные за пределами каждой области обещания. Есть ли проверенный и надежный способ сделать это?
Изменить - Кажется, что async
/await
- лучший способ сделать это, но я запускаю Node на Heroku, и он еще не поддерживается:/
Ответы
Ответ 1
Ну, вы можете использовать что-то вроде этого с promises:
myArray.map(x => convertX)
.filter()
.whatever()
.etc()
если вы используете мой rsp модуль из числа npm.
Кроме того, вы можете использовать функции async
/await
ES2017 для упрощения цепей promises, особенно их области.
Потому что с таким кодом:
db.query(first query)
.then(storeFirstQuery)
.then(secondQueryAndStoreIt)
.then(thirdQueryAndStoreIt)
.catch(errHandlingFunction)
если вам нужно использовать результат первого запроса в последнем обработчике thirdQueryAndStoreIt()
, у вас возникла проблема с доступом к данным, выходящим за рамки. Но когда вы это сделаете:
try {
let a = await db.query(first query);
let b = await storeFirstQuery();
let c = await secondQueryAndStoreIt();
let d = await thirdQueryAndStoreIt(a); // use 'a' here
} catch (e) {
errHandlingFunction(e);
}
тогда у вас нет проблемы с областью видимости, так как вы можете легко получить доступ ко всем ранее назначенным переменным.
См. это для версий Node, поддерживающих этот синтаксис:
Вы можете использовать его с Node v7.6 + из коробки или с помощью Node v7.0 + с флагом --harmony
.
Для более старых версий Node вы можете использовать co или Bluebird.coroutine для аналогичного синтаксиса с использованием функций генератора и yield
вместо await
.
Ответ 2
если вы действительно этого хотите, вы можете ограничить область применения одним мета-обещанием, создав его самостоятельно:
return new Promise((resolve, reject) => {
const f1 = () => { /* ... */ };
const f2 = () => { /* ... */ };
const f3 = () => { /* ... */ };
return db.query()
.then(f1)
.then(f2)
.then(f3)
.then(resolve)
.catch(reject);
});
но самый читаемый способ сделать это - использовать async
/await
.