Почему исключения используются для отклонения promises в JS?

Спецификация, на которую я имею в виду, находится в http://promises-aplus.github.io/promises-spec/.

При использовании then() вы можете либо вернуть обещание, либо отклонить обещание, когда захотите, либо вы можете отбросить исключение, чтобы отклонить обещание.

Почему api не был разработан таким образом, что для функции then он передал функцию разрешения и отклонения, такую ​​как исходный конструктор обещаний?

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

Ответ 1

Почему не был создан api таким образом, чтобы для функции then была передана функция разрешения и отклонения, как исходный конструктор обещаний?

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

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

Я однажды реализовал Promise lib с необязательными аргументами resolve/reject, но было утомительно использовать - и я редко нуждался в них из-за # 4. Использование их было подвержено ошибкам, вы могли бы легко забыть что-то (например, ошибки обработки или события прогресса) - точно так же, как люди, которые вручную создают и возвращают отложенные ответы, которые разрешены из обещаний callback, вместо вызова then.

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

Они не предназначены для использования в потоке управления (например, ветвление, петли и т.д.), но для обработки исключений: отклонения являются исключительными, Большинство разработчиков Promise хотели реализовать их в качестве альтернативы синхронному (блокирующему) коду - где IO всегда бросали исключения, поэтому они адаптировали это. Отклонения по-прежнему объясняются как асинхронный эквивалент try … catch, хотя их монадический характер может быть использован более мощными способами и приложениями более высокого уровня.

Создание целого нового объекта обещания и его возврат, просто чтобы отклонить его, добавляет код раздувания IMO.

Здесь нет большой разницы между return new RejectedPromise(…), return reject(…) и throw Error(…).

Отладка становится сложнее и в случае возникновения исключения (например, синтаксические ошибки или функция вызывается на объект undefined и т.д.)

Большинство разработчиков Promise, похоже, считают это преимуществом на самом деле - (неожиданные) исключения, даже в асинхронном коде, будут автоматически пойманы, поэтому их можно обработать, а не взорвать программу (незаметно). См. Также обработка исключений, сброшенные ошибки в promises и приемлемый шаблон обещания для ошибок LOUD?.