簡體   English   中英

試圖了解 Javascript 腳本執行順序。 試過異步、延遲、動態加載腳本,結果都出乎意料

[英]Trying to understand Javascript script execution order. Tried async, defer, dynamically loading scripts and all have unpredictable results

我有以下代碼,根據代碼我假設操作的順序是:

  1. 腳本 one.js 將被下載並執行,這將更新 dom,它會立即更新 div1 並顯示在瀏覽器中。
  2. sleep function 將在 sleep 命令下方暫停運行 8 秒
  3. 腳本 two.js 將被下載並執行,dom 更新並顯示在瀏覽器中
  4. 腳本 three.js 將被下載並執行,dom 更新並顯示在瀏覽器中

然而,事實並非如此。 在 sleep 命令完成之前,瀏覽器中不會顯示/更新任何內容。 在控制台中,在“ONE start”之前記錄了“SLEEP start”。

我嘗試在調用 loadScript 時啟用異步,我已經將 sleep 命令移到了 two.js 中。 沒有什么變化。 我在這里想念什么? 我將如何更改我的代碼以實現正確的下載和執行?

這是我的代碼:

html:

<!doctype html>
<html lang="en">
<body>

    <div id="div1" style="background-color: orange;">
    </div>

    <script>
        function sleep(milliseconds) {
            const date = Date.now();
            let currentDate = null;
            do {
                currentDate = Date.now();
                //console.log('sleep is executing');
            } while (currentDate - date < milliseconds);
        }

        function loadScript(src, async_enabled = async_enabled) {
            let script = document.createElement('script');
            script.src = src;
            script.async = async_enabled;
            document.body.append(script);
        }

        loadScript("one.js", async_enabled = false);
        console.log('SLEEP start');
        sleep(8000);
        console.log('SLEEP stop');
        loadScript("two.js", async_enabled = false);
        loadScript("three.js", async_enabled = false);
    </script>

</body>
</html>

一個.js:

    console.log('ONE start');
    let one = document.getElementById('div1');
    let p1 = document.createElement('p');
    p1.innerHTML = 'One';
    one.appendChild(p1);
    console.log('ONE stop');

二.js:

    console.log('TWO start');
    let two = document.getElementById('div1');
    let p2 = document.createElement('p');
    p2.innerHTML = 'Two';
    two.appendChild(p2);
    console.log('TWO stop');

three.js:

    console.log('THREE start');
    let three = document.getElementById('div1');
    let p3 = document.createElement('p');
    p3.innerHTML = 'Three';
    three.appendChild(p3);
    console.log('THREE stop');

更新我只是使用 sleep 命令來幫助我了解 js 腳本是如何加載和執行的(順序)。 我真的不想在我的代碼中使用 sleep 命令。 我將 html 更改為:

<!doctype html>
<html lang="en">
<body>

    <div id="div1" style="background-color: orange;">
    </div>

    <script>
        function sleep(milliseconds) {
            const date = Date.now();
            let currentDate = null;
            do {
                currentDate = Date.now();
                //console.log('sleep is executing');
            } while (currentDate - date < milliseconds);
        }

        function loadScript(src, async_enabled = async_enabled) {
            let script = document.createElement('script');
            script.src = src;
            script.async = async_enabled;
            document.body.append(script);
        }

        loadScript("one.js", async_enabled = false);
    </script>
</body>
</html>

將 one.js 更改為:

    console.log('ONE start');
    let one = document.getElementById('div1');
    let p1 = document.createElement('p');
    p1.innerHTML = 'One';
    one.appendChild(p1);
    console.log('ONE stop');
    loadScript("two.js", async_enabled = false);

並將 two.js 更改為:

    console.log('TWO start');
    sleep(5000);
    let two = document.getElementById('div1');
    let p2 = document.createElement('p');
    p2.innerHTML = 'Two';
    two.appendChild(p2);
    console.log('TWO stop');

我仍然得到相同的結果。 我知道我應該理解為什么會發生這種情況,但我還沒有明白。 那么如何更改代碼以使 one.js 中發生的事情立即顯示在瀏覽器中?

  1. 您的sleep是忙碌的睡眠,由於各種原因,這是一個壞主意。 尤其是在瀏覽器中的 JavaScript 中,所有內容都有效地以單線程運行。 這意味着當您的代碼處於“睡眠”狀態時,不會執行涉及 JavaScript 的任何其他內容。

  2. 您的loadScript方法將一個新元素附加到 DOM,這會立即發生。 在當前的 JavaScript 運行完成之前無法開始執行新腳本,這就是為什么所有通過loadScript加載的腳本只有在您睡眠才會開始運行。

解決此問題的正確方法是在瀏覽器中采用 JavaScript 的事件驅動性質,而不是嘗試在繁忙的循環中“保持運行”。

如果您想“睡覺”,您只需安排新代碼稍后運行並從調用中返回。

順便說一句,這也會釋放 JavaScript 事件循環來處理諸如加載其他腳本之類的事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM