JS Promises: Выполнение vs Разрешение

Я понимаю, что Promises существует в одном из трех состояний: Promise может быть ожидающим (неразрешенным), выполнено (успешно разрешено) или отклонено (разрешено неудачно).

Чтение через A + Promise Spec и Документация MDN, Я смущен тем, что оба они признают выполненные и отклоненные состояния, но в определении конструктора Promise они указывают два обратных вызова: разрешить и отклонить. Кажется, мы используем эти два термина взаимозаменяемо; они не являются.

Не означает успеха:

re·solve /rəˈzälv/ verb
1. settle or find a solution to (a problem, dispute, or contentious matter).

Имеет ли смысл успех:

ful·fill /fo͝olˈfil/ verb
1. bring to completion or reality; achieve or realize (something desired, promised, or predicted).
2. carry out (a task, duty, or role) as required, pledged, or expected.

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

Ответ 1

Мы можем решить обещание с другим обещанием.

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

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

a().then(() => new Promise(setTimeout)).catch(e => console.error(e));

В этом случае мы говорим, что обещание "разрешено" другому обещанию, и оно остается в ожидании.

then все это происходит за нашими спинами, так что может быть проще взглянуть на старинный случай, когда a не поддерживает обещания (принимает обратные вызовы), и мы не корректируем вещи правильно:

// Old times and unflattened for exposition:
new Promise((resolve, reject) => a(function(result) {
  resolve(new Promise(setTimeout));
}, reject))
.then(() => console.log("after setTimeout"))
.catch(e => console.error(e));

Здесь мы видим более ясно, что решение вызвано с другим обещанием. Важно отметить, что разрешенное обещание не выполняет и не "after setTimeout" сообщение "after setTimeout" до тех пор, пока не будет разрешено второе обещание (с undefined значением, не являющимся обещанием от setTimeout), после чего оба обещания становятся выполненными (другими словами: эти два обещания только что сформировались решительная цепочка).

Это ключ к пониманию того, что решено отличается от выполненного или даже выполненного (выполненного или отклоненного, а не ожидающего решения).

Из штатов и судеб:

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

Судьба относится к тому, была ли достигнута судьба единого обещания, и не связана ли она напрямую с каким-либо переходом государства из-за цепей решимости.

Ответ 2

Разрешенный Promise, имеющий значение Error, не автоматически преобразует Promise в отклоненный Promise

var p = Promise.resolve(new Error("rejected"));
p.then(function(data) {
  console.log(data, p)
})

Ответ 3

Я думаю, что принято говорить, что Обещание разрешилось или улажено. Решение обещания - это процесс, в котором обещание переходит из состояния pending и получает значение, связанное с указанным состоянием. Таким образом, если обещание будет либо fulfilled, либо rejected, это будет разрешенное обещание (по мере окончания процесса разрешения). Если обещание входит в процесс разрешения и никогда не переходит в какое-либо другое государство, говорят, что обещание не решено (процесс разрешения так и не закончился).

Что касается других терминов rejected или fulfilled, они являются двумя другими состояниями, в которых может перейти от a pending. reject довольно очевиден IMO, он обрабатывает случаи, когда предполагается сбой. Теперь я согласен с тем, что fulfill может быть несколько неоднозначным, потому что это может просто означать, что обещание завершилось успешно (как при разрешении). Он не должен описывать процесс разрешения, а успех (или отсутствие ошибки) в задаче.

Процесс разрешения (для решения обещания) можно увидеть в A + spec.

Edit.

Причина, по которой люди обычно используют resolve в качестве первого имени аргумента, потому что обратный вызов, переданный как первый аргумент, вызывает процесс разрешения. Он не выполняет обещание (обещание все еще может быть отклонено), оно только начинает решать обещание. Механизм reject не специфицирован в спецификации, он на самом деле является коротким замыканием процесса разрешения, так что обещание разрешено с помощью reject (фактически не разрешено).

Вот несколько примеров, когда p отклоняется с помощью resolve:

Это точка 2.3.1.

var p = new Promise(resolve => setTimeout(() => resolve(p), 0));

Это точка 2.3.2.3.

var p = Promise.resolve(Promise.reject('reason'));

Это точка 2.3.3.2.

var thenable = { get then() { throw new Error(); } }
var p = Promise.resolve(thenable);

Это точка 2.3.3.3.3

var thenable = {
    then: function(resolvePromise, rejectPromise){
        rejectPromise(new Error());
    }
}
var p = Promise.resolve(thenable);

Это точка 2.3.3.4.2

var thenable = {
    then: function(){
        throw new Error();
    }
}
var p = Promise.resolve(thenable);

Я использовал здесь Promise.resolve вместо первого аргумента функции, переданной в конструктор Promise, но они должны быть одинаковыми. Много раз функция resolve, передаваемая конструктору, имеет следующий вид:

var p = this;
var cb = function(x){
    resolve(p, x);
}

Конечно, вы можете записать эти тесты как:

var p = new Promise(function(resolve){
    resolve(thenable);
});

Ответ 4

Действительно, обратный вызов разрешения не означает, что обещание будет выполнено.

Термины "выполнено", "отклонено", " ожидают", "решены", "разрешены" и "заблокированы" определены в спецификациях EcmaScript2015, 25.4 Объекты Promise:

Любой объект Promise находится в одном из трех взаимоисключающих состояний: выполнено, отклонено и ожидает рассмотрения:

  • Обещание p выполняется, если p.then(f, r) немедленно поставит в очередь задание для вызова функции f.

  • Обещание p отклоняется, если p.then(f, r) немедленно поставит в очередь задание для вызова функции r.

  • Обещание ожидает рассмотрения, если оно не выполнено и не отклонено.

Обещание считается выполненным, если оно не ожидает рассмотрения, т.е. Если оно выполнено или отклонено.

Обещание разрешается, если оно выполнено или "заблокировано" для соответствия состоянию другого обещания. Попытка разрешить или отклонить выполненное обещание не имеет никакого эффекта. Обещание не разрешено, если оно не выполнено. Нерешенное обещание всегда находится в состоянии ожидания. Выполненное обещание может быть отложено, выполнено или отклонено.

Краткий обзор, где я буду использовать термин "автономный" как противоположность "заблокирован". Это два возможных значения для ситуации с обещаниями:

+---------------------+------------+-----------+-----------+----------+
| action              | dependency | state     | resolved? | settled? |
+---------------------+------------+-----------+-----------+----------+
| new Promise()       | autonomous | pending   |    no     |    no    |
| - resolve(thenable) | locked-in  | pending*  |    yes    |    no    |
| - resolve(other)    | autonomous | fulfilled |    yes    |    yes   |
| - reject(any)       | autonomous | rejected  |    yes    |    yes   |
+---------------------+------------+-----------+-----------+----------+

* Теперь можно контролировать будущее состояние объекта обещания.

Приведенная выше цитата упоминает, что обещание заблокировано, чтобы соответствовать состоянию "другого обещания", но более точно, что "другое обещание" также может быть "обещанием", которое невозможно выполнить, как это видно на этапах 11 и 12 описание процесса в 25.4.1.3.2

  1. Если IsCallable (thenAction) имеет значение false, то
    а. Вернуть FulfillPromise (обещание, разрешение).
  2. Выполнить EnqueueJob ("PromiseJobs", PromiseResolveThenableJob, "обещание, разрешение, затем действие")

Демонстрация resolve вызывается с помощью thenable, что в свою очередь вызывает отклонение:

const thenable = { // Could be a promise object, but does not have to be
    then(success, fail) {
        setTimeout(() => fail("gotcha!"), 1000);
    }
}

const p = new Promise((resolve, reject) => {
    console.log("1. The promise is created as pending");
    setTimeout(() => {
        resolve(thenable);
        console.log("2. It resolved with a thenable; it not yet settled");
    }, 1000);
});

p.catch(err => 
   console.log('3. It settled as rejected with error message "${err}"')
);