<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 在JavaScript的世界中,所有代碼都是單線程執行的。 由于這個“缺陷”,導致JavaScript的所有網絡操作,瀏覽器事件,都必須是異步執行。異步執行可以用回調函數實現: ``` function callback() { console.log('Done'); } console.log('before setTimeout()'); setTimeout(callback, 1000); // 1秒鐘后調用callback函數 console.log('after setTimeout()'); ``` 觀察上述代碼執行,在Chrome的控制臺輸出可以看到: ``` before setTimeout() after setTimeout() (等待1秒后) Done ``` 可見,異步操作會在將來的某個時間點觸發一個函數調用。 AJAX就是典型的異步操作。以上一節的代碼為例: ``` request.onreadystatechange = function () { if (request.readyState === 4) { if (request.status === 200) { return success(request.responseText); } else { return fail(request.status); } } } ``` 把回調函數`success(request.responseText)`和`fail(request.status)`寫到一個AJAX操作里很正常,但是不好看,而且不利于代碼復用。 有沒有更好的寫法?比如寫成這樣: ``` var ajax = ajaxGet('http://...'); ajax.ifSuccess(success) .ifFail(fail); ``` 這種鏈式寫法的好處在于,先統一執行AJAX邏輯,不關心如何處理結果,然后,根據結果是成功還是失敗,在將來的某個時候調用`success`函數或`fail`函數。 古人云:“君子一諾千金”,這種“承諾將來會執行”的對象在JavaScript中稱為Promise對象。 Promise有各種開源實現,在ES6中被統一規范,由瀏覽器直接支持。先測試一下你的瀏覽器是否支持Promise: ``` 'use strict'; new Promise(function () {}); // 直接運行測試: alert('支持Promise!'); ``` 我們先看一個最簡單的Promise例子:生成一個0-2之間的隨機數,如果小于1,則等待一段時間后返回成功,否則返回失敗: ``` function test(resolve, reject) { var timeOut = Math.random() * 2; log('set timeout to: ' + timeOut + ' seconds.'); setTimeout(function () { if (timeOut < 1) { log('call resolve()...'); resolve('200 OK'); } else { log('call reject()...'); reject('timeout in ' + timeOut + ' seconds.'); } }, timeOut * 1000); } ``` 這個`test()`函數有兩個參數,這兩個參數都是函數,如果執行成功,我們將調用`resolve('200 OK')`,如果執行失敗,我們將調用`reject('timeout in ' + timeOut + ' seconds.')`。可以看出,`test()`函數只關心自身的邏輯,并不關心具體的`resolve`和`reject`將如何處理結果。 有了執行函數,我們就可以用一個Promise對象來執行它,并在將來某個時刻獲得成功或失敗的結果: ``` var p1 = new Promise(test); var p2 = p1.then(function (result) { console.log('成功:' + result); }); var p3 = p2.catch(function (reason) { console.log('失敗:' + reason); }); ``` 變量`p1`是一個Promise對象,它負責執行`test`函數。由于`test`函數在內部是異步執行的,當`test`函數執行成功時,我們告訴Promise對象: ``` // 如果成功,執行這個函數: p1.then(function (result) { console.log('成功:' + result); }); ``` 當`test`函數執行失敗時,我們告訴Promise對象: ``` p2.catch(function (reason) { console.log('失敗:' + reason); }); ``` Promise對象可以串聯起來,所以上述代碼可以簡化為: ``` new Promise(test).then(function (result) { console.log('成功:' + result); }).catch(function (reason) { console.log('失敗:' + reason); }); ``` 實際測試一下,看看Promise是如何異步執行的: ``` 'use strict'; // 清除log: var logging = document.getElementById('test-promise-log'); while (logging.children.length > 1) { logging.removeChild(logging.children[logging.children.length - 1]); } // 輸出log到頁面: function log(s) { var p = document.createElement('p'); p.innerHTML = s; logging.appendChild(p); } new Promise(function (resolve, reject) { log('start new Promise...'); var timeOut = Math.random() * 2; log('set timeout to: ' + timeOut + ' seconds.'); setTimeout(function () { if (timeOut < 1) { log('call resolve()...'); resolve('200 OK'); } else { log('call reject()...'); reject('timeout in ' + timeOut + ' seconds.'); } }, timeOut * 1000); }).then(function (r) { log('Done: ' + r); }).catch(function (reason) { log('Failed: ' + reason); }); ``` Log: 可見Promise最大的好處是在異步執行的流程中,把執行代碼和處理結果的代碼清晰地分離了: ![promise](img/l9.png) Promise還可以做更多的事情,比如,有若干個異步任務,需要先做任務1,如果成功后再做任務2,任何任務失敗則不再繼續并執行錯誤處理函數。 要串行執行這樣的異步任務,不用Promise需要寫一層一層的嵌套代碼。有了Promise,我們只需要簡單地寫: ``` job1.then(job2).then(job3).catch(handleError); ``` 其中,`job1`、`job2`和`job3`都是Promise對象。 下面的例子演示了如何串行執行一系列需要異步計算獲得結果的任務: ``` 'use strict'; var logging = document.getElementById('test-promise2-log'); while (logging.children.length > 1) { logging.removeChild(logging.children[logging.children.length - 1]); } function log(s) { var p = document.createElement('p'); p.innerHTML = s; logging.appendChild(p); } // 0.5秒后返回input*input的計算結果: function multiply(input) { return new Promise(function (resolve, reject) { log('calculating ' + input + ' x ' + input + '...'); setTimeout(resolve, 500, input * input); }); } // 0.5秒后返回input+input的計算結果: function add(input) { return new Promise(function (resolve, reject) { log('calculating ' + input + ' + ' + input + '...'); setTimeout(resolve, 500, input + input); }); } var p = new Promise(function (resolve, reject) { log('start new Promise...'); resolve(123); }); p.then(multiply) .then(add) .then(multiply) .then(add) .then(function (result) { log('Got value: ' + result); }); ``` Log: `setTimeout`可以看成一個模擬網絡等異步執行的函數。現在,我們把上一節的AJAX異步執行函數轉換為Promise對象,看看用Promise如何簡化異步處理: ``` 'use strict'; // ajax函數將返回Promise對象: function ajax(method, url, data) { var request = new XMLHttpRequest(); return new Promise(function (resolve, reject) { request.onreadystatechange = function () { if (request.readyState === 4) { if (request.status === 200) { resolve(request.responseText); } else { reject(request.status); } } }; request.open(method, url); request.send(data); }); } var log = document.getElementById('test-promise-ajax-result'); var p = ajax('GET', '/api/categories'); p.then(function (text) { // 如果AJAX成功,獲得響應內容 log.innerText = text; }).catch(function (status) { // 如果AJAX失敗,獲得響應代碼 log.innerText = 'ERROR: ' + status; }); ``` Result: 除了串行執行若干異步任務外,Promise還可以并行執行異步任務。 試想一個頁面聊天系統,我們需要從兩個不同的URL分別獲得用戶的個人信息和好友列表,這兩個任務是可以并行執行的,用`Promise.all()`實現如下: ``` var p1 = new Promise(function (resolve, reject) { setTimeout(resolve, 500, 'P1'); }); var p2 = new Promise(function (resolve, reject) { setTimeout(resolve, 600, 'P2'); }); // 同時執行p1和p2,并在它們都完成后執行then: Promise.all([p1, p2]).then(function (results) { console.log(results); // 獲得一個Array: ['P1', 'P2'] }); ``` 有些時候,多個異步任務是為了容錯。比如,同時向兩個URL讀取用戶的個人信息,只需要獲得先返回的結果即可。這種情況下,用`Promise.race()`實現: ``` var p1 = new Promise(function (resolve, reject) { setTimeout(resolve, 500, 'P1'); }); var p2 = new Promise(function (resolve, reject) { setTimeout(resolve, 600, 'P2'); }); Promise.race([p1, p2]).then(function (result) { console.log(result); // 'P1' }); ``` 由于`p1`執行較快,Promise的`then()`將獲得結果`'P1'`。`p2`仍在繼續執行,但執行結果將被丟棄。 如果我們組合使用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>

                              哎呀哎呀视频在线观看