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

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # Promise https://github.com/javascript-tutorial/zh.javascript.info/blob/master/1-js/11-async/02-promise-basics/article.md 想象一下,你自己是一位頂尖歌手,粉絲沒日沒夜地詢問你下個單曲何時到來。 為了從中解放,你承諾會在單曲發布的第一時間通知他們。你讓粉絲們填寫了他們的個人信息,因此他們會在歌曲發布的第一時間獲取到。即使遇到了不測,歌曲可能永遠不會被發行,他們也會被通知到。 每個人都很開心:你不會被任何人催促;粉絲也不會錯過單曲發行的第一時間。 在編程中,我們經常用現實世界中的事物進行類比: 1. "生產者代碼" 會做一些事情,也需要事件。比如,它加載一個遠程腳本。此時它就像“歌手”。 2. "消費者代碼" 想要在它準備好時知道結果。許多函數都需要結果。此時它們就像是“粉絲”。 3. **promise**是將兩者連接的一個特殊的 JavaScript 對象。就像是“列表”。生產者代碼創建它,然后將它交給每個訂閱的對象,因此它們都可以訂閱到結果。 這種類比并不精確,因為 JavaScipt promises 比簡單的列表更加復雜:它們擁有額外的特性和限制。但是它們仍然有相似之處。 Promise 對象的構造語法是: ~~~js let promise = new Promise(function(resolve, reject) { // executor (生產者代碼,"singer") }); ~~~ 傳遞給`new Promise`的函數稱之為**executor**。當 promise 被創建時,它會被自動調用。它包含生產者代碼,這最終會產生一個結果。與上文類比,executor 就是“歌手”。 `promise`對象有內部屬性: * `state`—— 最初是 "pending",然后被改為 "fulfilled" 或 "rejected", * `result`—— 一個任意值,最初是`undefined`。 當 executor 完成任務時,應調用下列之一: * `resolve(value)`—— 說明任務已經完成: * 將`state`設置為`"fulfilled"`, * sets`result`to`value`。 * `reject(error)`—— 表明有錯誤發生: * 將`state`設置為`"rejected"`, * 將`result`設置為`error`。 [![](https://github.com/javascript-tutorial/zh.javascript.info/raw/master/1-js/11-async/02-promise-basics/promise-resolve-reject.png)](https://github.com/javascript-tutorial/zh.javascript.info/blob/master/1-js/11-async/02-promise-basics/promise-resolve-reject.png) 這是一個簡單的 executor,可以把這一切都聚集在一起: ~~~js let promise = new Promise(function(resolve, reject) { // 當 promise 被構造時,函數會自動執行 alert(resolve); // function () { [native code] } alert(reject); // function () { [native code] } // 在 1 秒后,結果為“完成!”,表明任務被完成 setTimeout(() => *!*resolve("done!")*/!*, 1000); }); ~~~ 我們運行上述代碼后發現兩件事: 1. 會自動并立即調用 executor(通過`new Promise`)。 2. executor 接受兩個參數`resolve`和`reject`—— 這些函數來自于 JavaScipt 引擎。我們不需要創建它們,相反,executor 會在它們準備好時進行調用。 經過一秒鐘的思考后,executor 調用`resolve("done")`來產生結果: [![](https://github.com/javascript-tutorial/zh.javascript.info/raw/master/1-js/11-async/02-promise-basics/promise-resolve-1.png)](https://github.com/javascript-tutorial/zh.javascript.info/blob/master/1-js/11-async/02-promise-basics/promise-resolve-1.png) 這是“任務成功完成”的示例。 現在的是示例則是 promise 的 reject 出現于錯誤的發生: ~~~js let promise = new Promise(function(resolve, reject) { // after 1 second signal that the job is finished with an error setTimeout(() => *!*reject(new Error("Whoops!"))*/!*, 1000); }); ~~~ [![](https://github.com/javascript-tutorial/zh.javascript.info/raw/master/1-js/11-async/02-promise-basics/promise-reject-1.png)](https://github.com/javascript-tutorial/zh.javascript.info/blob/master/1-js/11-async/02-promise-basics/promise-reject-1.png) 總之,executor 應該完成任務(通常會需要時間),然后調用`resolve`或`reject`來改變 promise 對象的對應狀態。 Promise 結果應該是 resolved 或 rejected 的狀態被稱為 "settled",而不是 "pending" 狀態的 promise。 ~~~ executor 只會調用 `resolve` 或 `reject`。Promise 的最后狀態一定會變化。 對 `resolve` 和 `reject` 的深層調用都會被忽略: ```js let promise = new Promise(function(resolve, reject) { resolve("done"); reject(new Error("…")); // 被忽略 setTimeout(() => resolve("…")); // 被忽略 }); ``` executor 所做的任務可能只有一個結果或者一個錯誤。在編程中,還有其他允許 "flowing" 結果的數據結構。例如流和隊列。相對于 promise,它們有著自己的優勢和劣勢。它們不被 JavaScipt 核心支持,而且缺少 promise 所提供的某些語言特性,我們在這里不對 promise 進行過多的討論。 同時,如果我們使用另一個參數調用 `resolve/reject` —— 只有第一個參數會被使用,下一個會被忽略。 ~~~ ```smart header="Reject with`Error`objects" 從技術上來說,我們可以使用任何類型的參數來調用 `reject`(就像 `resolve`)。但建議在 `reject`(或從它們中繼承)中使用 `Error` 對象。 錯誤原因就會顯示出來。 ~~~ ````smart header="Resolve/reject can be immediate" 實際上,executor 通常會異步執行一些動作,然后在一段時間后調用 `resolve/reject`,但它不必那么做。我們可以立即調用 `resolve` 或 `reject`,就像這樣: ```js let promise = new Promise(function(resolve, reject) { resolve(123); // immediately give the result: 123 }); ~~~ 比如,當我們開始做一個任務時,它就會發生,然后發現一切都已經被做完了。從技術上來說,這非常好:我們現在有了一個 resolved promise。 ~~~ ```smart header="The `state` and `result` are internal" Promise 的 `state` 和 `result` 屬性是內部的。我們不能從代碼中直接訪問它們,但是我們可以使用 `.then/catch` 來訪問,下面是對此的描述。 ``` ## 消費者:".then" 和 ".catch" Promise 對象充當生產者(executor)和消費函數之間的連接 —— 那些希望接收結果/錯誤的函數。假設函數可以使用方法 `promise.then` 和 `promise.catch` 進行注冊。 `.then` 的語法: ```js promise.then( function(result) { /* handle a successful result */ }, function(error) { /* handle an error */ } ); ``` 第一個函數參數在 promise 為 resolved 時被解析,然后得到結果并運行。第二個參數 —— 在狀態為 rejected 并得到錯誤時使用。 例如: ```js run let promise = new Promise(function(resolve, reject) { setTimeout(() => resolve("done!"), 1000); }); // resolve 在 .then 中運行第一個函數 promise.then( *!* result => alert(result), // 在 1 秒后顯示“已經完成!” */!* error => alert(error) // 不會運行 ); ``` 在 rejection 的情況下: ```js run let promise = new Promise(function(resolve, reject) { setTimeout(() => reject(new Error("Whoops!")), 1000); }); // reject 在 .then 中運行第二個函數 promise.then( result => alert(result), // 無法運行 *!* error => alert(error) // 在 1 秒后顯示 "Error: Whoops!" */!* ); ``` 如果我們只對成功完成的情況感興趣,那么我們只為 `.then` 提供一個參數: ```js run let promise = new Promise(resolve => { setTimeout(() => resolve("done!"), 1000); }); *!* promise.then(alert); // 在 1 秒后顯示 "done!" */!* ``` 如果我們只對錯誤感興趣,那么我們可以對它使用 `.then(null, function)` 或 "alias":`.catch(function)` ```js run let promise = new Promise((resolve, reject) => { setTimeout(() => reject(new Error("Whoops!")), 1000); }); *!* // .catch(f) 等同于 promise.then(null, f) promise.catch(alert); // 在 1 秒后顯示 "Error: Whoops!" */!* ``` 調用 `.catch(f)` 是 `.then(null, f)` 的模擬,這只是一個簡寫。 ````smart header="On settled promises `then` runs immediately" 如果 promise 為 pending 狀態,`.then/catch` 處理器必須要等待結果。相反,如果 promise 已經被處理,它們就會立即執行: ```js run // 一個立即變成 resolve 的 promise let promise = new Promise(resolve => resolve("done!")); promise.then(alert); // 完成!(現在顯示) ``` 這對于有時需要時間而且有時要立即完成的任務來說非常方便。確保處理器在兩種情況下都能夠運行。 ~~~ ````smart header="`.then/catch`的處理器總是異步的" 更確切地說,當 `.then/catch` 處理器應該執行時,它會首先進入內部隊列。JavaScript 引擎從隊列中提取處理器,并在當前代碼完成時執行 `setTimeout(..., 0)`。 換句話說,`.then(handler)`會被觸發,會執行類似于`setTimeout(handler, 0)`的動作。 在下述示例中,promise 被立即 resolved,因此`.then(alert)`被立即觸發:`alert`會進入隊列,在代碼完成之后立即執行。 ~~~js // an immediately resolved promise let promise = new Promise(resolve => resolve("done!")); promise.then(alert); // 完成!(在當前代碼完成之后) alert("code finished"); // 這個 alert 會最先顯示 ~~~ 因此在`.then`之后的代碼總是在處理器之前被執行(即使實在預先解決 promise 的情況下)。通常這并不重要,只會在特定情況下才會重要。 ~~~ 我們現在研究一下 promises 如何幫助我們編寫異步代碼的示例。 ## 示例:loadScript 我們已經從之前的章節中加載了 `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 ` + src)); document.head.append(script); } ``` 我們用 promises 進行重寫。 `loadScript` 新函數不需要請求回調函數,取而代之的是它會創建并返回一個在加載完成時的 promise 對象。外部代碼可以使用 `.then` 向其添加處理器: ```js run function loadScript(src) { return new Promise(function(resolve, reject) { let script = document.createElement('script'); script.src = src; script.onload = () => resolve(script); script.onerror = () => reject(new Error("Script load error: " + src)); document.head.append(script); }); } ``` 用法: ```js run let promise = loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"); promise.then( script => alert(`${script.src} is loaded!`), error => alert(`Error: ${error.message}`) ); promise.then(script => alert('One more handler to do something else!')); ``` 我們立刻看到基于回調語法的好處: ```compare minus="Callbacks" plus="Promises" - 在調用 `loadScript` 時,我們必須已經有了一個 `callback` 函數。換句話說,在調用 `loadScript` **之前**我們必須知道如何處理結果。 - 只能有一個回調。 + Promises 允許我們按照自然順序進行編碼。首先,我們運行 `loadScript` 和 `.then` 來編寫如何處理結果。 + 無論何時,只要我們有需要,就可以在 promise 中調用 `.then`。 ``` 因此,promise 已經為我們的編碼帶來了更好的編碼方式和靈活性。我們會在之后章節看到更多相關內容。 ~~~
                  <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>

                              哎呀哎呀视频在线观看