Почему `async/await` не работает в моем случае?

Я читаю о async/await, но у меня есть критический вопрос. Сначала я объясняю старый пример, чтобы показать базу моего вопроса, а затем задаю свой точный вопрос.

Все это знают:

console.log('1');
console.log('2');
console.log('3'); // Ex: 123

Это просто, но в следующем случае:

console.log('1');
setTimeout(()=>{
    console.log('2');
},0);
console.log('3'); // Ex: 132

Это тоже просто, setTimeout функция asynchronous а также JavaScript спрыгнуть с него и после разрешения запустить его функцию, так что мы видим 2 после 1 а также 3,

Но теперь я читаю async/await и я написал такую ​​функцию:

(async function test() {
    console.log('1');
    await setTimeout(()=>{
        console.log('2');
    },0);
    console.log('3');
})(); // Ex: 132

Экспорт 132 тоже почему? это мой вопрос, почему 3 беги раньше 2? Я ожидаю из-за async/await после 1 JavaScript ждет 2 а потом написал 3, Зачем 132?

3 ответа

Решение

await только приостанавливается, когда переданное ему значение является Promise, В твоем случае, setTimeout возвращает Number так что ждите, не ждите этого.

Правильный код будет следующим:

async function test() {
    console.log('1');
    await new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('2');
            resolve()
        }, 0);
    });
    console.log('3');
}

Так как setTimeout не возвращает обещание. await x ждет только если x это обещание; если x это не обещание, оно (эффективно) заключено в один, как будто вы await Promise.resolve(x), Это означает, что код, следующий за ним, будет работать асинхронно, но как можно скорее.*

Если вы хотите обещанную версию setTimeout см . ответы на этот вопрос. Но даже с этим, ваш test функция не будет использовать обратный вызов, вместо этого вы просто будете ждать тайм-аут с включенным обещанием:

function later(delay) {
    return new Promise(function(resolve) {
        setTimeout(resolve, delay);
    });
}

async function test() {
  console.log("1");
  await later(10);
  console.log("2");
  console.log("3");
}

test().catch(e => console.error(e));
console.log("After the call (just to prove it does wait for the timeout after 1 and before 2");


* В браузерах это гарантированно будет до setTimeout(..., 0) запланировано во время той же задачи, потому что обратные вызовы обещания, запланированные во время задачи, происходят сразу после окончания этой задачи, до того, как следующая задача будет выбрана из очереди (даже если следующая задача была запланирована до обратного вызова обещания). Подробнее об этом ("макрозадачи" и "микрозадачи") в ответах на этот вопрос.

Вы можете await к тем функциям, которые возвращаются Promise, setTimeout не возвращается Promise, Так что в этом случае await используется до setTimeout не имеет смысла.

Вы можете обернуть setTimeout в обещание и позвонить решить на setTimeout функция.

(async function test() {
    console.log('1');
    await new Promise((resolve, reject) => { 
         setTimeout(() => {
            console.log('2');
            resolve(); // also can pass a parameter here to get it via await.
         },0);
    });
    console.log('3');
})();

Другие вопросы по тегам