Обещание # все против последовательных ждет - разница во временном разрешении - PullRequest
0 голосов
/ 13 января 2019

В следующем фрагменте время разрешения отличается при использовании обещания # все и последовательно ожидает каждого обещания. Я хочу глубоко понять, что происходит, так как это кажется предостережением при работе с производительностью.

* Редактировать: добавлен еще один случай без вызова функции, возможно, я что-то упустил из-за того, как работает await

// Code goes here

window.onload = function() {
  
    let p = new Promise((res, rej) => {
        setTimeout(() => {
            res('p OK')
        }, 5000);
    })
   
    let p2 = new Promise((res, rej) => {
        setTimeout(() => {
            res('p2 OK')
        }, 5000);
    })
    
    let p3 = new Promise((res, rej) => {
        setTimeout(() => {
            res('p3 OK')
        }, 5000);
    })
  
    async function pp() {
        return new Promise((res, rej) => {
            setTimeout(() => {
                res('pp OK');
            }, 5000);
        });
    }
  
    async function a() {
        let out = await Promise.all([p, pp()]);
        return `#a ${out}`;
    }
  
    async function b() {
       let out1 = await p;
       let out2 = await pp();
       return `#b ${out1} ${out2}`;
    }
    
    async function c() {
        let out1 = await p;
        let out2 = await p2;
        let out3 = await p3;
        return `#c ${out1} ${out2} ${out3}`;
    }
  
    let out1 = document.getElementById("out1");
    let out2 = document.getElementById("out2");
    let out32 = document.getElementById("out2");
    const date = new Date().getSeconds();
    a().then(x => console.log(x)).then(() => out1.innerHTML += `finished after ${new Date().getSeconds() - date}s`);
    b().then(x => console.log(x)).then(() => out2.innerHTML += `finished after ${new Date().getSeconds() - date}s`);
    c().then(x => console.log(x)).then(() => out3.innerHTML += `finished after ${new Date().getSeconds() - date}s`);

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>

<head>
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
</head>

<body>
    <p id="out1">
        Promise#all  
    </p>
    <p id="out2">
        Sequential awaits
    </p>
    <p id="out3">
        Sequential awaits without executing fnc
    </p>
</body>

</html>

Ответы [ 2 ]

0 голосов
/ 13 января 2019

Некоторые моменты, которые могут прояснить ситуацию:

  • Функция обратного вызова конструктора, которая передается в new Promise, выполняется немедленно , что означает, что задержка setTimeout включается в в тот момент , собираетесь ли вы ждать или нет.

  • Следовательно, тайм-ауты, созданные p, p2 и p3, запускаются сразу после инициализации этих переменных. Поскольку все они будут отключены через 5 секунд, соответствующие обещания (p, p2 и p3) будут разрешены примерно в одно и то же время. Опять же, это не зависит от того, используете ли вы await, then, Promise.all или просто забыли об этих обещаниях и ничего с ними не делаете.

  • В отличие от этого, функция pp - это просто функция. Это не обещание. Только когда вы на самом деле вызываете эту функцию, вы создаете обещание с соответствующим временем ожидания, которое инициируется.

  • await заставляет функцию async немедленно возвращать , возвращая обещание. Это означает, что остальная часть кода функции откладывается, но не остальная часть вашего другого кода Javascript: функция возвращается и выполнение продолжается после вызова этой функции. Когда стек вызовов пуст, будут обрабатываться разные очереди событий. Так что это не блокировка. Как только обещание, переданное await, разрешается, происходит нечто волшебное: контекст выполнения функции async восстановлен , и выполнение возобновляется до следующего await. Если больше нет await для выполнения, и функция достигает своего конца, обещание, которое она возвратила (когда встретила первый await), будет разрешено .

  • Promise.all не влияет на решение отдельных обещаний. Он создает новое обещание, которое разрешается, когда все данные обещания разрешены. Как объяснялось выше, обещания в вашем случае (p, p2) разрешаются примерно в один и тот же момент, поэтому Promise.all также разрешается примерно через 5 секунд.

  • Если вы делаете await pp(), вы создаете это обещание только тогда и не раньше. И поскольку перед вами стоит await p, для выполнения pp() потребуется 5 секунд. Таким образом, соответствующий тайм-аут не начинается , пока эта секунда await не будет выполнена. Вот почему await p; await pp() занимает дважды 5 секунд для разрешения.

  • Дело обстоит иначе, когда вы делаете await p; await p2. Там оба обещания уже были созданы, и их таймауты уже начались. Поэтому, когда через 5 секунд первый await закончится, JS перейдет ко второму await и обнаружит, что p2 также разрешен. Не будет никакого дополнительного периода ожидания (за исключением асинхронного управления, где await всегда будет помещать событие в очередь микрозадач)

Я думаю, что с этими элементами вы можете правильно представить, как будет выполняться код, и как вы получите ожидаемый результат.

0 голосов
/ 13 января 2019

В первой функции она выполняет pp сразу, чтобы запустить тайм-аут обещания. Во второй функции он ждет, пока p не будет завершено, прежде чем выполнить pp, чтобы запустить тайм-аут обещания.

Ключевое слово await блокирует выполнение до тех пор, пока обещание не разрешится, прежде чем перейти к следующей строке.

RE: обновление

В вашем третьем примере все обещания запускаются в то время. Ключевое слово await ожидает разрешения. Поскольку все ваши обещания начинаются в одно и то же время, все они разрешатся в очень маленькой дельте. К тому времени, когда вы нажмете await p2, это, вероятно, уже решено. То же самое для p3.

Во втором примере pp не начинается, пока не завершится p.

[*] Это на самом деле не блокирует выполнение, но это влияет на ваш код.

...