Когда выполняется тело обещания?

Предположим, что у меня есть следующий Promise:

function doSomethingAsynchronous() {
  return new Promise((resolve) => {
    const result = doSomeWork();

    setTimeout(() => {
      resolve(result);
   }), 100);
  });
}

В какой момент времени называется doSomeWork()? Является ли это сразу после или когда построено Promise? Если нет, есть ли что-то дополнительное, что мне нужно сделать явно, чтобы убедиться, что тело Promise запущено?

Ответ 1

Немедленно, да, по спецификации.

Из MDN:

Функция-исполнитель немедленно выполняется реализацией Promise, передавая функции разрешения и отклонения (исполнитель вызывается до того, как конструктор Promise даже возвращает созданный объект)

Здесь это указано в спецификации ECMAScript (конечно, труднее читать...): http://www.ecma-international.org/ecma-262/6.0/#sec-promise-executor

Эта гарантия может быть важной, например, когда вы готовите несколько promises, затем переходите к all или race, или когда ваши исполнители имеют синхронные побочные эффекты.

Ответ 2

Да, когда вы создаете Promise первый параметр выполняется немедленно.

В общем случае вы бы не использовали promise так, как вы это делали, поскольку в текущей реализации оно все равно будет синхронным.

Вы бы предпочли реализовать его с таймаутом или вызвать функцию разрешения как часть обратного вызова ajax

function doSomethingAsynchronous() {
  return new Promise((resolve) => {
    setTimeout(function() {
      const result = doSomeWork();
      resolve(result);
    }, 0);
  });
}

Затем метод setTimeout вызовет функцию в следующий момент, когда очередь событий свободна.

Ответ 3

Вы можете видеть, что снизу тело выполняется немедленно, просто помещая в тело синхронный код, а не асинхронный:

function doSomethingAsynchronous() {
  return new Promise((resolve) => {
    console.log("a");
    resolve("promise result");
  });
}
doSomethingAsynchronous();console.log("b");

Результат показывает, что тело обещания выполняется немедленно (до того, как будет напечатано "b"):

a
b

Результат Обещания сохраняется, чтобы быть переданным вызову then, например:

doSomethingAsynchronous().then(function(pr){console.log("c:"+pr);});console.log("b");

Результат:

a
b
c:promise result

То же самое относится к асинхронному коду в теле, за исключением неопределенной задержки перед выполнением обещания и вызовом "then" (точка "c"). Таким образом, "a" и "b" будут напечатаны, как только doSomethingAsynchronous() вернется, но "c" появится только тогда, когда обещание выполнено (вызывается "resol").

Что выглядит странным на первый взгляд, после добавления вызова "then", так это то, что "b" печатается перед "c", даже когда все синхронно. Конечно, "а" будет печатать, затем "с" и, наконец, "б"? Причина, по которой "a", "b" и "c" печатаются в таком порядке, заключается в том, что независимо от того, является ли код в теле асинхронным или синхронизированным, метод "then" всегда вызывается Promise асинхронно.

В моем представлении я представляю, что метод then вызывается чем-то вроде setTimeout(function(){then(pr);},0); в Обещании однажды "решиться" называется. Т.е. текущий путь выполнения должен завершиться до того, как будет выполнена функция, переданная в then.

Из спецификации Promise не очевидно, почему это происходит. Я предполагаю, что это обеспечивает согласованное поведение в отношении того, когда вызывается then (всегда после завершения текущего потока выполнения), что, по-видимому, позволяет объединять/объединять несколько Promises перед тем, как запускать все then вызовы подряд.

Ответ 4

Из спецификации EcmaScript http://www.ecma-international.org/ecma-262/6.0/#sec-promise-executor

Функция executor выполняется немедленно Promise реализация, передача функций разрешения и отклонения (исполнитель вызывается еще до того, как конструктор Promise вернет созданный объект)

Рассмотрим следующий код:

var executorFunction = (resolve, reject) => {
    console.log("This line will be printed as soon as we declare the promise");
    if(asynkTaskCompleted){
        resolve("Pass resolved Value here");
    }else{
        reject("Pass reject reason here");
    }

}
const myPromise = new Promise(executorFunction);

Когда мы выполняем приведенный выше код, executorFunction будет вызываться автоматически, как только мы объявим обещание, без необходимости его явного вызова.

Ответ 5

Да, поскольку вызов синхронный, он будет вызываться немедленно, прежде чем присоединить какие-либо ".then" или ".catch".

Обещание уже будет разрешено к моменту присоединения первого ".then", и оно немедленно спустит значение разрешения.