Why does the Promise object block rendering?

落花浮王杯 提交于 2019-12-17 21:15:04

问题


I was testing the Promise object and wrote some code that simulates a long running task that is synchronous. I was comparing Promise and setTimeout - see fiddle:

<!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>

I thought Promise and setTimeout would behave in a similar way, add the code to the task queue and then continue the execution. The order of the results are the same but the promise with a long running task seems to block the rendering until the long running task completes. Can someone explain this?

The example runs best in Chrome.

Update: I'm not trying to make the long running task to run in parallel, I just want to understand why Promise and setTimeout behave differently in my example. But if you do want to run the task in parallel then Web Workers / Worker threads is the way to go as Quentin suggests.

But the answer to my question seems to be that Promise constructors are synchronous as Bergi writes in a comment. Here is a longer explanation


回答1:


while (Date.now() - nu < 1000) {} doesn't simulate a long running task that is syncronous. It is a long running task that is syncronous.

Promises are a way to manage asynchronous code, not a way to make code asynchronous, nor a way to simulate multithreading.

For that, you need to look at workers.

  • Web Workers for browsers.
  • Worker Threads for Node.js.


来源:https://stackoverflow.com/questions/53044306/why-does-the-promise-object-block-rendering

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!