Работа resolve в promise

290
06 марта 2017, 12:09

Есть такой код, один аспект которого мне не понятен:

    'use strict'; 
     
    let promise = new Promise((resolve, reject) => { 
      resolve("Промис завершился"); 
      console.log("Промис ждет, пока я появлюсь"); 
    }); 
     
    promise 
      .then( 
        result => console.log("Fulfilled: " + result),  
        error => console.log("Rejected: " + error)  
      );

Собственно, не понятно то, что алерт в функции-конструкторе вообще отрабатывает своё и появляется. И сразу же за ним (это прям вообще не понятно - почему за ним?) появляется "промис завершился".
Не понятно по какому принципу работает resolve(), то есть передается управление обработчику .then.
Я много раз видел, когда resolve() помещали конкретно внутрь обработчика onload (для ajax запросов, например), который сам по себе говорит о завершенности выполнения вопроса. А получается, что resolve() можно запихнуть хоть с самого начала и код ниже всё равно отработает.
Да, конечно, в случае с ajax можно ожидать отклонение запроса сервером, поэтому нужно использовать resolve() в случае успеха, а reject() в случае ошибки.
Помогите разобраться.

Answer 1

В JS остановить функцию может только или return, ошибка или её конец.
Почитать.

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

Если Вам этого не нужно, используйте return: return resolve();.

Answer 2

resolve() обычная коллбэк функция, вызов который говорит промису перейти в выполненое состояние. resolve() не останавливает выполнение функции внутри промиса.

Answer 3

Приведу цитату из статьи, что бы не ошибиться:

Согласно стандарту, у объекта new Promise(executor) при создании есть четыре внутренних свойства:

PromiseState – состояние, вначале «pending».

PromiseResult – результат, при создании значения нет.

PromiseFulfillReactions – список функций-обработчиков успешного выполнения.

PromiseRejectReactions – список функций-обработчиков ошибки.

Когда функция-executor вызывает reject или resolve, то PromiseState становится "resolved" или "rejected", а все функции-обработчики из соответствующего списка перемещаются в специальную системную очередь "PromiseJobs".

Эта очередь автоматически выполняется, когда интерпретатору «нечего делать».

То есть resolve не сразу вызывает функцию, а ждет окончания функции-executor, которую передали при создании promise-a

Answer 4

Промис(обещание) сам по себе никого не ждёт.
Просто у вас есть возможность обрабатывать как синхронный, так и асинхронный код.
Созданный Promise исполняется сразу же, синхронно(на самом деле это зависит от реализации), а своих подписчиков(then) уведомляет на следующем такте event-loop.

Давайте рассмотрим его поведение на примере:

'use strict'; 
     
    let promise = new Promise((resolve, reject) => { 
      resolve("Промис завершился"); 
      console.log("1. Promise created"); 
    }); 
    console.log('2. After creation'); 
    promise 
      .then( 
        result => console.log("3. Resolved: " + result), 
        error => console.log("Rejected: " + error)  
      ); 
    console.log('2.5 функция в .then тем не менее будет вызвана позже');

Как видите, Promise при создании сразу(синхронно) запустил свой executor, но обработчик в then будет вызван на следующей итерации eventLoop.

Пример внутренней реализации(очень урезанной):

function Thennable(executor) { 
  let thenList = []; 
  let state = 0; // 1 - resolved, 2 - rejected 
  let value = null; 
  // executor вызывается сразу же, синхронно 
  executor( 
    res => {  
      thenList.forEach(then =>  
        // обработчики вызываются асинхронно. 
        setTimeout(() => then[0](res))); 
      state = 1; 
      value = res; 
    }, 
    error => {  
      thenList.forEach(then =>  
        setTimeout(() => then[1](error)) 
      ); 
      state = 2; 
      value = error; 
    } 
  ); 
  this.then = (onResolve, onReject) => { 
    if (state == 0) {// ещё не обработано, добавим в очередь ожидающих 
      thenList.push([onResolve, onReject]); 
    } else if (state == 1) { // resolved 
      onResolve(value); 
    } else if (state == 2) { // rejected 
      onReject(value); 
    } 
    // return new Thennable(...) 
  };   
} 
 
let p = new Thennable((ok, fail) => { 
  ok('resolved'); 
  console.log('1 created'); 
}); 
console.log('2 after create'); 
p.then(res => console.log(3, res))

READ ALSO