Есть такой код, один аспект которого мне не понятен:
'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()
в случае ошибки.
Помогите разобраться.
В JS остановить функцию может только или return
, ошибка или её конец.
Почитать.
В ожидании используется некий асинхронный подход (иначе не вышло бы отлавливать асинхронные операции, Ваш КО): при разрешении обещания, коллбэк встаёт в очередь до завершения ожидающего кода в функции и только потом вызывается.
Если Вам этого не нужно, используйте return
: return resolve();
.
resolve()
обычная коллбэк функция, вызов который говорит промису перейти в выполненое состояние. resolve()
не останавливает выполнение функции внутри промиса.
Приведу цитату из статьи, что бы не ошибиться:
Согласно стандарту, у объекта new Promise(executor) при создании есть четыре внутренних свойства:
PromiseState – состояние, вначале «pending».
PromiseResult – результат, при создании значения нет.
PromiseFulfillReactions – список функций-обработчиков успешного выполнения.
PromiseRejectReactions – список функций-обработчиков ошибки.
Когда функция-executor вызывает reject или resolve, то PromiseState становится "resolved" или "rejected", а все функции-обработчики из соответствующего списка перемещаются в специальную системную очередь "PromiseJobs".
Эта очередь автоматически выполняется, когда интерпретатору «нечего делать».
То есть resolve
не сразу вызывает функцию, а ждет окончания функции-executor
, которую передали при создании promise-a
Промис(обещание) сам по себе никого не ждёт.
Просто у вас есть возможность обрабатывать как синхронный, так и асинхронный код.
Созданный 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))
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты