Сохранение цепочек обещаний

Я привык обещать цепочки массивов. Очень просто прочитать цепочку обещаний, когда каждое обещание занимает одну строку, например

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,

Другие вопросы по тегам