Когда отклонять/разрешать обещание

Я думаю о том, когда именно мне нужно отказаться от обещания. Я нашел пару вопросов по этой теме, но не смог найти правильный ответ. Когда мне следует отклонить обещание?

Эта статья http://howtonode.org/6666a4b74d7434144cff717c828be2c3953d46e7/promises говорит:

  • Решение. Успешное обещание "разрешено", которое вызывает ожидающих слушателей успеха и запоминает значение, которое было разрешено для будущих слушателей успеха, которые прилагаются. Разрешение соотносится с возвращенным значением.
  • Отклонить: Когда встречается условие ошибки, Promise "отклоняется", который вызывает ожидающие прослушиватели ошибок и запоминает значение, которое было отклонено для будущих приложников ошибок, которые прилагаются. Отклонение коррелирует с выбранным исключением.

Это основной принцип? Это только отвергает обещание, если произошло исключение?

Но в случае такой функции, как

findUserByEmail()

Я бы ожидал, что функция вернет пользователя, так что я могу продолжить цепочку без проверки результата

findUserByEmail()
    .then(sendWelcomeBackEmail)
    .then(doSomeNiceStuff)
    .then(etc..)

Каковы наилучшие/распространенные практики?

Ответ 1

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

Отклонение обещания, как и исключение, полезно для потока управления. Он не должен представлять собой поистине непредвиденную ошибку; он может представлять проблему, которую вы полностью ожидаете и обрабатываете:

function getProfile(email) {
  return getProfileOverNetwork(email)
    .then(null, function (err) {
      //something went wrong getting the profile
      if (err.code === 'NonExistantUser') {
        return defaultUser;
      } else if (profileCached(email)) {
        return getProfileFromCache(email);//fall back to cached profile
      } else {
        throw err;//sometimes we don't have a nice way of handling it
      }
    })
}

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

В общем, везде, где это возможно, если вы пытаетесь написать какой-то асинхронный код, вы должны подумать: "Что бы я написал, если бы это было синхронно". Обычно это довольно простая трансформация, чтобы получить от этого обещанный эквивалент. A nice example of where rejected promises might be used is in an существует`:

function exists(filePath) {
  return stat(filePath) //where stat gets last updated time etc. of the file
    .then(function () { return true; }, function () { return false; })
}

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

function existsSync(filePath) {
  try {
    statSync(filePath);
    return true;
  } catch (ex) {
    return false;
  }
}

Ваш пример

Возвращаясь к вашему примеру:

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

Иногда может быть полезно просто вернуть null вместо этого, но это будет зависеть от вашей логики приложений и, вероятно, не лучший способ пойти.

Ответ 2

Я знаю, откуда вы. Документация Q и Q может с легкостью считать, что отложенное/обещание отклонено - это все об обработке исключений.

Это не обязательно так.

Отложенная может быть отклонена по любой причине, требуемой вашим приложением.

Отложенные/promises - все об обработке ответов от асинхронных процессов, и каждый асинхронный процесс может привести к множеству результатов, некоторые из которых являются "успешными" и "неудачными". Вы можете отказаться от своей отсрочки - по любой причине, независимо от того, был ли результат номинально успешным или неудачным, и без исключения, когда-либо брошенного либо в javascript, либо в асинхронном процессе.

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