Будет ли обещание Javascript ES6 поддерживать «готовое» API?

Например

p = new Promise(function (resolve, reject) {
    throw 'err';
});

p.done();

В большинстве промисных полифилловых библиотек done вызовет ошибку, и текущее выполнение завершится.

Но если мы используем p.then(), ничего не произойдет. Ошибка поглощается обещанием. Если мы используем p.catch, у нас нет возможности выйти из текущего выполнения. Я хочу добиться чего-то вроде:

try {
    // something
} catch (err) {
    if (check(err)) {
        throw err;
    }
}

person Yad Smood    schedule 31.10.2014    source источник
comment
Все полезное на html5rocks.com/en/tutorials/es6/promises.   -  person jmort253    schedule 31.10.2014
comment
Вот почему рекомендуется использовать библиотеку Promise, такую ​​как bluebird. Bluebird может очень хорошо обрабатывать неперехваченные исключения, предоставляя вам стопку обещаний, ведущих к текущему событию. См. метод longStackTraces в объекте Bluebird Promise.   -  person Madara's Ghost    schedule 31.10.2014
comment
Нативные промисы @SecondRikudo также в конечном итоге, вероятно, все будут делать это - они уже делают это, например, в Firefox.   -  person Benjamin Gruenbaum    schedule 31.10.2014
comment
Обратите внимание, что этот вопрос устарел с ES2015.   -  person    schedule 09.07.2016


Ответы (3)


No.

Мало того, что .done, скорее всего, не будет поддерживаться в будущих версиях спецификации — в нем нет необходимости. Цитата из тем, на которые ссылался Мариуш:

Доменик:

он по-прежнему подвержен ошибкам: если вы ошибетесь и не будете следовать правилу хотя бы раз, вы можете замолчать ошибку навсегда.

Марк Миллер (первооткрыватель концепции обещаний):

Обратите внимание, что слабые ссылки, надеюсь, в ES7 предоставят нам один из диагностических инструментов, необходимых для преодоления этого пробела. С помощью слабых ссылок, если отклоненное обещание собирается без уведомления каких-либо обработчиков, мы можем организовать генерацию диагностики. Реализация промиса должна будет хранить причину в исполнителе промиса (посмертном обработчике gc), чтобы у него была диагностика, чтобы сообщить после обнаружения, что промис был отклонен.

Иегуда Кац об обработчике ошибок RSVP:

Подход, который мы используем в RSVP, заключается в установке монитора необработанных обещаний, который выдает по умолчанию.

Вы можете исключить конкретное обещание из этого поведения, присоединив обработчик сбоев noop, если вы знаете, что будете присоединять обработчики асинхронных ошибок. У нас, вероятно, будет сахар для этого (.undone :p)

По нашему опыту, перенос бремени буквально со всех на людей, которые могут захотеть подключить асинхронные обработчики ошибок, уместно.

И из фактического репо, предшествовавшего спецификации, Доменик сказал:

Выполненная работа будет выполнена путем интеграции функции отслеживания необработанных отклонений в инструменты разработки. Большинство TC39ers, насколько я понимаю, а также я сам, считают, что этого достаточно для завершения спецификации.


Спецкомитет не просто проигнорировал .done, они сочли его ненужным и подверженным ошибкам. Новые современные библиотеки промисов автоматически обнаруживают необработанные отказы — два примера этого — промисы When и промисы Bluebird, в которых впервые появилась эта идея.

.done — это артефакт, возникший из-за того, что браузер не смог обнаружить необработанные отклонения. Правда в том, что обнаружить их детерминистически невозможно, но в подавляющем большинстве случаев это вполне возможно.

Не верите мне? Откройте Firefox и поиграйте с его родными промисами:

p = new Promise(function (resolve, reject) {
    throw 'err';
});
// Logs as error: Unhandled error: `err`

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

Теперь проблема заключается в том, что нативные промисы еще не очень пригодны для использования - поскольку в IE они не существуют, а в Chrome еще не реализовано обнаружение необработанного отклонения - но это происходит, и оно будет там. В то же время вы можете использовать совместимую с ES6 библиотеку, например Bluebird, которая сделает это за вас.

Если вы хотите сделать полифилл (что я настоятельно не рекомендую) — у полифилла от torazaburo есть несколько недостатков. Он объявляет перечисляемое свойство в прототипе промиса, и, как правило, это не то, как была разработана спецификация - ожидается, что вы создадите промисы подкласса, чтобы расширить их, а не исправите их обезьяной - к сожалению, в настоящее время нет реализаций, поддерживающих это .

Итак, вкратце:

  • Подождите, пока собственные промисы стабилизируются, прежде чем использовать их — тем временем вы можете использовать библиотеки, которые реализуют спецификацию, например Bluebird. Когда ситуация стабилизируется, отсутствие .done вообще не будет проблемой.
  • Используйте шаблоны для обнаружения ошибок — например, проверьте средство удаления шаблон здесь.
  • Используйте инструменты разработчика, когда они доступны, длинные трассировки стека и асинхронная отладка — большие плюсы. Также обратите внимание, что вы не должны бросать строки, если вам нужны значимые трассировки стека.

Удачи и счастливого кодирования.

person Benjamin Gruenbaum    schedule 31.10.2014

Нет, AFAIK done не является частью спецификации. Чтобы имитировать его поведение, вы должны сгенерировать исключение на следующем тике, вне сферы действия цепочки обещаний:

p.catch(function(e) { 
    setTimeout(function() { throw e; });
});

По сути, это то, как библиотеки реализуют done. См. выдержку из документов Q:

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

Реализация done самостоятельно

Если вы хотите реализовать приблизительную семантику done в обычном понимании, тогда что-то вроде:

Promise.prototype.done = function(onFulfilled, onRejected) {
    this
        .then(onFulfilled, onRejected)
        .catch(function(e) {
            setTimeout(function() { throw e; });
        })
    ;
};

Настройка обработчика ошибок

Если вы хотите иметь возможность самостоятельно обрабатывать эти ошибки, вы можете настроить обработчик ошибок:

Promise.onError = function(e) {
    console.log("The sky is falling", e);
    throw e;
};

Затем вызовите обработчик на следующем тике:

Promise.prototype.done = function(onFulfilled, onRejected) {
    this
        .then(onFulfilled, onRejected)
        .catch(function(e) {
            setTimeout(Promise.onError || function() { throw e; }, 1, e);
        })
    ;
};
person Community    schedule 31.10.2014

Текущее утверждение TC39 заключается в том, что эта проблема может и должна быть решена изначально в браузерных движках с инструментами разработчика. Вот почему они против предоставления done в собственном API.

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

https://github.com/domenic/promises-unwrapping/issues/19

http://mozilla.6506.n7.nabble.com/Where-d-Promise-done-go-td281461.html

https://github.com/promises-aplus/promises-spec/issues/43

https://github.com/slightlyoff/Promises/issues/33

person Mariusz Nowak    schedule 31.10.2014
comment
Хотя я категорически не согласен с вашим мнением, я действительно ценю вашу самоотверженность и участие в этих дискуссиях. Кроме того, спасибо, что разместили их здесь, они очень актуальны. Хороший ответ о контексте. - person Benjamin Gruenbaum; 31.10.2014