Сохранение цепочек обещаний
Я привык обещать цепочки массивов. Очень просто прочитать цепочку обещаний, когда каждое обещание занимает одну строку, например
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
})
Теперь, это может быть разборчиво, но когда цепочка обещаний расширяется, это становится немного больше. Если я даю каждому обещанию его собственную функцию, то я могу упростить процесс, чтобы код выглядел примерно так (что, в свою очередь, в 1000 раз более разборчиво).
db.query(first query)
.then(storeFirstQuery)
.then(secondQueryAndStoreIt)
.then(thirdQueryAndStoreIt)
.catch(errHandlingFunction)
Таким образом, я могу переставить функции без необходимости манипулировать значениями, которые передаются от одного обещания к другому. Если обещание использует результат другого, оно должно быть только после другого, но не сразу после. Таким образом, я могу выполнять обещания везде, где мне нужно.
Однако это требует, чтобы моя цепочка обещаний использовала переменные вне области действия каждого обещания. Есть ли проверенный и верный способ сделать это?
Редактировать - Кажется async
/await
это лучший способ сделать это, но я использую Node на Heroku, и он пока не поддерживается:/
2 ответа
Ну, вы можете использовать что-то подобное с обещаниями:
myArray.map(x => convertX)
.filter()
.whatever()
.etc()
если вы используете мой модуль rsp из npm.
Помимо этого вы можете использовать async
/await
Особенности ES2017 упрощают цепочки обещаний, особенно их объем.
Потому что с таким кодом:
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
,
Если вы действительно хотите, вы можете ограничить область действия одним мета-обещанием, создав его самостоятельно:
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
,