Почему объект Promise блокирует рендеринг?

1

Я тестировал объект Promise и написал код, который имитирует длительную задачу, которая является синхронной. Я сравнивал Promise и setTimeout - см. Скрипку:

<!DOCTYPE html>
<html>

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

  <body>
    <h2>Promise vs setTimeout</h2>
    <div><button id="settimeout-test">setTimeout with slow running function</button></div>
    <div><button id="promise-test">Promise and slow running function</button></div>
    <div><button id="clear">Clear Results</button></div>
    <h5>Results</h5>
    <div id="result"></div>

    <script>
        const slow = function() {
            let nu = Date.now();
            while (Date.now() - nu < 1000) {}
        }
        const getSlowPromise = () => new Promise(resolve => {
                slow();
                resolve();
        });
        const resultsElement = document.getElementById('result')
        const log = (message) => {
            resultsElement.innerText += message;
        }  

        const settimeoutButton = document.getElementById('settimeout-test');
        settimeoutButton.addEventListener('click', () => {
            const now = Date.now();
            log('\nsetTimeout test starts after ${Date.now() - now} ms');
            setTimeout(() => {
                slow();
                log('\nSlow function completes after ${Date.now() - now} ms');
            }, 0);
            log('\nEvent listener completes after ${Date.now() - now} ms');
        });

        const promiseButton = document.getElementById('promise-test');
        promiseButton.addEventListener('click', () => {
            const now = Date.now();
            log('\nsetTimeout test starts after ${Date.now() - now} ms');
            getSlowPromise().then(res => log('\nPromise completes after ${Date.now() - now} ms'));
            log('\nevent listener completes after ${Date.now() - now} ms');
        })

        const clear = () => resultsElement.innerText = '';
        const clearButton = document.getElementById('clear');
        clearButton.addEventListener('click', () => clear());

    </script>

  </body>

</html>

Я думал, что Promise и setTimeout будут вести себя аналогичным образом, добавьте код в очередь задач, а затем продолжите выполнение. Порядок результатов один и тот же, но обещание с долговременной задачей, похоже, блокирует рендеринг, пока не завершится длительная работа. Может кто-нибудь объяснить это?

Пример лучше всего работает в Chrome.

Обновление: я не пытаюсь запустить параллельное выполнение задачи, я просто хочу понять, почему Promise и setTimeout ведут себя по-другому в моем примере. Но если вы хотите запустить задачу параллельно, то потоки Web Workers/Worker - это путь, который предлагает Quentin.

Но ответ на мой вопрос, похоже, заключается в том, что конструкторы Promise синхронны, как пишет Bergi в комментарии. Вот более длинное объяснение

  • 3
    потому что while (Date.now() - nu < 1000) {} блокирует рендеринг - обещания не while (Date.now() - nu < 1000) {} подобные синхронные циклы
  • 1
    Вызовы, поставленные в очередь setTimeout также выполняются в другой части цикла событий, чем микротрубы, такие как вызовы Promise.then . Хотя это не проблема с вашим примером кода, это вызовет у вас проблемы, если вы ожидаете, что они будут эквивалентны во всех случаях.
Показать ещё 3 комментария
Теги:
settimeout
promise
es6-promise

1 ответ

5

while (Date.now() - nu < 1000) {} не моделирует длительную выполняемую задачу, которая является синхронной. Это давно работает задача, которая является Синхронной.

Обещания - это способ управления асинхронным кодом, а не способ сделать асинхронный код, а также способ имитации многопоточности.

Для этого вам нужно посмотреть на рабочих.

  • 0
    Вы правы в том, что это долгосрочное задание, я просто хотел имитировать более значимое задание. Я думаю, что код является асинхронным, поскольку он фактически выполняет последний вызов функции журнала, прежде чем он запускает код внутри Promise или setTimeout в обоих случаях. Но он, конечно, не работает параллельно, поскольку JavaScript является однопоточным. Но я не пытаюсь работать параллельно, я просто пытаюсь понять, почему Promise и setTimeout ведут себя по-разному.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню