<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 簡介:回調 JavaScipt 中的許多動作都是**異步**的。 比如,這個`loadScript(src)`函數: ~~~js function loadScript(src) { let script = document.createElement('script'); script.src = src; document.head.append(script); } ~~~ 這個函數的作用是加載一個新的腳本。當使用`<script src="…">`將其添加到文檔中時,瀏覽器就會對它進行加載和執行。 我們可以像這樣使用: ~~~js // 加載并執行腳本 loadScript('/my/script.js'); ~~~ 函數是**異步**調用的,因為動作不是此刻(加載腳本)完成的,而是之后。 調用初始化腳本加載,然后繼續執行。當腳本正在被加載時,下面的代碼可能已經完成了執行,如果加載需要時間,那么同一時間,其他腳本可能也會被運行。 ~~~js loadScript('/my/script.js'); // 下面的代碼在加載腳本時,不會等待腳本被加載完成 // ... ~~~ 現在,我們假設想在新腳本被加載完成時,被立即使用。它可能聲明了新函數,因此我們想要運行它們。 但如果我們在`loadScript(…)`調用后,立即那么做,就會導致操作失敗。 ~~~js loadScript('/my/script.js'); // 腳本含有 "function newFunction() {…}" newFunction(); // 沒有這個函數! ~~~ 很明顯,瀏覽器沒有時間去加載腳本。因此,對新函數的立即調用失敗了。`loadScript`函數并沒有提供追蹤加載完成時方法。腳本加載然后最終的運行,僅此而已。但我們希望了解腳本何時加載完成,以使用其中的新函數和新變量。 我們將`callback`函數作為第二個參數添加至`loadScript`中,函數在腳本加載時被執行: ~~~js function loadScript(src, *!*callback*/!*) { let script = document.createElement('script'); script.src = src; script.onload = () => callback(script); document.head.append(script); } ~~~ 如果現在你想從腳本中調用新函數,我們應該在回調函數中那么寫: ~~~js loadScript('/my/script.js', function() { // 在腳本被加載后,回調才會被運行 newFunction(); // 現在起作用了 ... }); ~~~ 這是我們的想法:第二個參數是一個函數(通常是匿名的)會在動作完成后被執行。 這是一個可運行的真實腳本示例: ~~~js function loadScript(src, callback) { let script = document.createElement('script'); script.src = src; script.onload = () => callback(script); document.head.append(script); } *!* loadScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js', script => { alert(`Cool, the ${script.src} is loaded`); alert( _ ); // 在加載的腳本中聲明的函數 }); */!* ~~~ 這被稱為“基于回調”的異步編程風格。異步執行某些動作的函數,應該提供一個在函數完成時可以運行的`callback`參數。 我們`loadScript`中就是那么做的,但很明顯這是一般性的方法。 ## [](https://github.com/javascript-tutorial/zh.javascript.info/blob/master/1-js/11-async/01-callbacks/article.md#%E5%9C%A8%E5%9B%9E%E8%B0%83%E4%B8%AD%E5%9B%9E%E8%B0%83)在回調中回調 如何順序加載兩個腳本:先是第一個,然后是第二個? 最明顯的方法是將第二個`loadScript`調用放在回調中,就像這樣: ~~~js loadScript('/my/script.js', function(script) { alert(`Cool, the ${script.src} is loaded, let's load one more`); *!* loadScript('/my/script2.js', function(script) { alert(`Cool, the second script is loaded`); }); */!* }); ~~~ 在外部`loadScript`完成時,內部回調就會被回調。 如果我們還想要一個腳本呢? ~~~js loadScript('/my/script.js', function(script) { loadScript('/my/script2.js', function(script) { *!* loadScript('/my/script3.js', function(script) { // ...在所有腳本被加載后繼續操作 }); */!* }) }); ~~~ 因此,每一個動作都在回調內部。這對于新動作來說,非常好,但是其他動作卻并不友好,因此我們接下來會看到一些此方法的變體。 ## [](https://github.com/javascript-tutorial/zh.javascript.info/blob/master/1-js/11-async/01-callbacks/article.md#%E5%A4%84%E7%90%86%E9%94%99%E8%AF%AF)處理錯誤 上述示例中,我們并沒有考慮錯誤因素。假如加載失敗會如何?我們的回調應該可以立即對其做出響應。 這是可以跟蹤錯誤的`loadScript`改進版: ~~~js function loadScript(src, callback) { let script = document.createElement('script'); script.src = src; *!* script.onload = () => callback(null, script); script.onerror = () => callback(new Error(`Script load error for ${src}`)); */!* document.head.append(script); } ~~~ 成功時,調用`callback(null, script)`,否則調用`callback(error)`。 用法: ~~~js loadScript('/my/script.js', function(error, script) { if (error) { // handle error } else { // 成功加載腳本 } }); ~~~ 再一次強調,我們使用的`loadScript`方法是非常常規的。它被稱為 "error-first callback" 風格。 慣例是: 1. `callback`的第一個參數是為了錯誤發生而保留的。一旦發生錯誤,`callback(err)`就會被調用。 2. 第二個參數(如果有需要)用于成功的結果。此時`callback(null, result1, result2…)`將被調用。 因此單個`callback`函數可以同時具有報告錯誤以及傳遞返回結果的作用。 ## [](https://github.com/javascript-tutorial/zh.javascript.info/blob/master/1-js/11-async/01-callbacks/article.md#%E5%9B%9E%E8%B0%83%E9%87%91%E5%AD%97%E5%A1%94)回調金字塔 從第一步可以看出,這是異步編碼的一種可行性方案。的確如此,對于一個或兩個的簡單嵌套,這樣的調用看起來非常好。 但對于一個接一個的多個異步動作,代碼就會變成這樣: ~~~js loadScript('1.js', function(error, script) { if (error) { handleError(error); } else { // ... loadScript('2.js', function(error, script) { if (error) { handleError(error); } else { // ... loadScript('3.js', function(error, script) { if (error) { handleError(error); } else { *!* // ...加載所有腳本后繼續 (*) */!* } }); } }) } }); ~~~ 上述代碼中: 1. 我們加載`1.js`,如果沒有發生錯誤。 2. 我們加載`2.js`,如果沒有發生錯誤。 3. 我們加載`3.js`,如果沒有發生錯誤 —— 做其他操作`(*)`。 如果嵌套變多,代碼層次就會變深,維護難度也隨之增加,尤其是如果我們有一個不是`...`的真實代碼,就會包含更多的循環,條件語句等。 這有時稱為“回調地獄”或者“回調金字塔”。 [![](https://github.com/javascript-tutorial/zh.javascript.info/raw/master/1-js/11-async/01-callbacks/callback-hell.png)](https://github.com/javascript-tutorial/zh.javascript.info/blob/master/1-js/11-async/01-callbacks/callback-hell.png) 嵌套調用的“金字塔”在每一個異步動作中都會向右增長。很快就會失去控制。 因此這種編碼方式并不可取。 我們可以通過為每個動作編寫一個獨立函數來解決這一問題,就像這樣: ~~~js loadScript('1.js', step1); function step1(error, script) { if (error) { handleError(error); } else { // ... loadScript('2.js', step2); } } function step2(error, script) { if (error) { handleError(error); } else { // ... loadScript('3.js', step3); } } function step3(error, script) { if (error) { handleError(error); } else { // ...在所有腳本被加載后繼續 (*) } }; ~~~ 看到了么?效果一樣,但是沒有深層的嵌套了,因為我們使每個動作都有一個獨立的頂層函數。 這很有效,但代碼看起來就像是一個被分裂的表格。你可能注意到了,它的可讀性非常差。在閱讀時,需要在塊之間切換。這非常不方便,尤其是不熟悉代碼的讀者,他們甚至不知道該跳轉到何處。 名為`step*`的函數都是單一使用的,他們被創建的唯一作用就是避免“回調金字塔”。沒有人會在動作鏈之外重復使用它們。因此這里的命名空間非常雜亂。 或許還有更好的方法。 幸運地是,有其他方法可以避免回調金字塔。其中一個最好的方法是使用 "promises",我們將在下一章中詳細描述。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看