<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之旅 廣告
                ## 語法 `async`函數的語法規則總體上比較簡單,難點是錯誤處理機制。 ### 返回 Promise 對象 `async`函數返回一個 Promise 對象。 `async`函數內部`return`語句返回的值,會成為`then`方法回調函數的參數。 ~~~javascript async function f() { return 'hello world'; } f().then(v => console.log(v)) // "hello world" ~~~ 上面代碼中,函數`f`內部`return`命令返回的值,會被`then`方法回調函數接收到。 `async`函數內部拋出錯誤,會導致返回的 Promise 對象變為`reject`狀態。拋出的錯誤對象會被`catch`方法回調函數接收到。 ~~~javascript async function f() { throw new Error('出錯了'); } f().then( v => console.log(v), e => console.log(e) ) // Error: 出錯了 ~~~ ### Promise 對象的狀態變化 `async`函數返回的 Promise 對象,必須等到內部所有`await`命令后面的 Promise 對象執行完,才會發生狀態改變,除非遇到`return`語句或者拋出錯誤。也就是說,只有`async`函數內部的異步操作執行完,才會執行`then`方法指定的回調函數。 下面是一個例子。 ~~~javascript async function getTitle(url) { let response = await fetch(url); let html = await response.text(); return html.match(/<title>([\s\S]+)<\/title>/i)[1]; } getTitle('https://tc39.github.io/ecma262/').then(console.log) // "ECMAScript 2017 Language Specification" ~~~ 上面代碼中,函數`getTitle`內部有三個操作:抓取網頁、取出文本、匹配頁面標題。只有這三個操作全部完成,才會執行`then`方法里面的`console.log`。 ### await 命令 正常情況下,**`await`命令后面是一個 Promise 對象**,返回該對象的結果。如果不是 Promise 對象,就直接返回對應的值。 ~~~javascript async function f() { // 等同于 // return 123; return await 123; } f().then(v => console.log(v)) // 123 ~~~ 上面代碼中,`await`命令的參數是數值`123`,這時等同于`return 123`。 另一種情況是,`await`命令后面是一個`thenable`對象(即定義`then`方法的對象),那么`await`會將其等同于 Promise 對象。 ~~~javascript class Sleep { constructor(timeout) { this.timeout = timeout; } then(resolve, reject) { const startTime = Date.now(); setTimeout( () => resolve(Date.now() - startTime), this.timeout ); } } (async () => { const sleepTime = await new Sleep(1000); console.log(sleepTime); })(); // 1000 ~~~ 上面代碼中,`await`命令后面是一個`Sleep`對象的實例。這個實例不是 Promise 對象,但是因為定義了`then`方法,`await`會將其視為`Promise`處理。 這個例子還演示了如何實現休眠效果。JavaScript 一直沒有休眠的語法,但是借助`await`命令就可以讓程序停頓指定的時間。下面給出了一個簡化的`sleep`實現。 ~~~javascript function sleep(interval) { return new Promise(resolve => { setTimeout(resolve, interval); }) } // 用法 async function one2FiveInAsync() { for(let i = 1; i <= 5; i++) { console.log(i); await sleep(1000); } } one2FiveInAsync(); ~~~ `await`命令后面的 Promise 對象如果變為`reject`狀態,則`reject`的參數會被`catch`方法的回調函數接收到。 ~~~javascript async function f() { await Promise.reject('出錯了'); } f() .then(v => console.log(v)) .catch(e => console.log(e)) // 出錯了 ~~~ 注意,上面代碼中,`await`語句前面沒有`return`,但是`reject`方法的參數依然傳入了`catch`方法的回調函數。這里如果在`await`前面加上`return`,效果是一樣的。 任何一個`await`語句后面的 Promise 對象變為`reject`狀態,那么整個`async`函數都會中斷執行。 ~~~javascript async function f() { await Promise.reject('出錯了'); await Promise.resolve('hello world'); // 不會執行 } ~~~ 上面代碼中,第二個`await`語句是不會執行的,因為第一個`await`語句狀態變成了`reject`。 有時,我們希望即使前一個異步操作失敗,也不要中斷后面的異步操作。這時可以將第一個`await`放在`try...catch`結構里面,這樣不管這個異步操作是否成功,第二個`await`都會執行。 ~~~javascript async function f() { try { await Promise.reject('出錯了'); } catch(e) { } return await Promise.resolve('hello world'); } f() .then(v => console.log(v)) // hello world ~~~ 另一種方法是`await`后面的 Promise 對象再跟一個`catch`方法,處理前面可能出現的錯誤。 ~~~javascript async function f() { await Promise.reject('出錯了') .catch(e => console.log(e)); return await Promise.resolve('hello world'); } f() .then(v => console.log(v)) // 出錯了 // hello world ~~~ ### 錯誤處理 如果`await`后面的異步操作出錯,那么等同于`async`函數返回的 Promise 對象被`reject`。 ~~~javascript async function f() { await new Promise(function (resolve, reject) { throw new Error('出錯了'); }); } f() .then(v => console.log(v)) .catch(e => console.log(e)) // Error:出錯了 ~~~ 上面代碼中,`async`函數`f`執行后,`await`后面的 Promise 對象會拋出一個錯誤對象,導致`catch`方法的回調函數被調用,它的參數就是拋出的錯誤對象。具體的執行機制,可以參考后文的“async 函數的實現原理”。 防止出錯的方法,也是將其放在`try...catch`代碼塊之中。 ~~~javascript async function f() { try { await new Promise(function (resolve, reject) { throw new Error('出錯了'); }); } catch(e) { } return await('hello world'); } ~~~ 如果有多個`await`命令,可以統一放在`try...catch`結構中。 ~~~javascript async function main() { try { const val1 = await firstStep(); const val2 = await secondStep(val1); const val3 = await thirdStep(val1, val2); console.log('Final: ', val3); } catch (err) { console.error(err); } } ~~~ 下面的例子使用`try...catch`結構,實現多次重復嘗試。 ~~~javascript const superagent = require('superagent'); const NUM_RETRIES = 3; async function test() { let i; for (i = 0; i < NUM_RETRIES; ++i) { try { await superagent.get('http://google.com/this-throws-an-error'); break; } catch(err) {} } console.log(i); // 3 } test(); ~~~ 上面代碼中,如果`await`操作成功,就會使用`break`語句退出循環;如果失敗,會被`catch`語句捕捉,然后進入下一輪循環。 ### 使用注意點 第一點,前面已經說過,`await`命令后面的`Promise`對象,運行結果可能是`rejected`,所以最好把`await`命令放在`try...catch`代碼塊中。 ~~~javascript async function myFunction() { try { await somethingThatReturnsAPromise(); } catch (err) { console.log(err); } } // 另一種寫法 async function myFunction() { await somethingThatReturnsAPromise() .catch(function (err) { console.log(err); }); } ~~~ 第二點,多個`await`命令后面的異步操作,如果不存在繼發關系,最好讓它們同時觸發。 ~~~javascript let foo = await getFoo(); let bar = await getBar(); ~~~ 上面代碼中,`getFoo`和`getBar`是兩個獨立的異步操作(即互不依賴),被寫成繼發關系。這樣比較耗時,因為只有`getFoo`完成以后,才會執行`getBar`,完全可以讓它們同時觸發。 ~~~javascript // 寫法一 let [foo, bar] = await Promise.all([getFoo(), getBar()]); // 寫法二 let fooPromise = getFoo(); let barPromise = getBar(); let foo = await fooPromise; let bar = await barPromise; ~~~ 上面兩種寫法,`getFoo`和`getBar`都是同時觸發,這樣就會縮短程序的執行時間。 第三點,`await`命令只能用在`async`函數之中,如果用在普通函數,就會報錯。 ~~~javascript async function dbFuc(db) { let docs = [{}, {}, {}]; // 報錯 docs.forEach(function (doc) { await db.post(doc); }); } ~~~ 上面代碼會報錯,因為`await`用在普通函數之中了。但是,如果將`forEach`方法的參數改成`async`函數,也有問題。 ~~~javascript function dbFuc(db) { //這里不需要 async let docs = [{}, {}, {}]; // 可能得到錯誤結果 docs.forEach(async function (doc) { await db.post(doc); }); } ~~~ 上面代碼可能不會正常工作,原因是這時三個`db.post`操作將是并發執行,也就是同時執行,而不是繼發執行。正確的寫法是采用`for`循環。 ~~~javascript async function dbFuc(db) { let docs = [{}, {}, {}]; for (let doc of docs) { await db.post(doc); } } ~~~ 如果確實希望多個請求并發執行,可以使用`Promise.all`方法。當三個請求都會`resolved`時,下面兩種寫法效果相同。 ~~~javascript async function dbFuc(db) { let docs = [{}, {}, {}]; let promises = docs.map((doc) => db.post(doc)); let results = await Promise.all(promises); console.log(results); } // 或者使用下面的寫法 async function dbFuc(db) { let docs = [{}, {}, {}]; let promises = docs.map((doc) => db.post(doc)); let results = []; for (let promise of promises) { results.push(await promise); } console.log(results); } ~~~ 第四點,async 函數可以保留運行堆棧。 ~~~javascript const a = () => { b().then(() => c()); }; ~~~ 上面代碼中,函數`a`內部運行了一個異步任務`b()`。當`b()`運行的時候,函數`a()`不會中斷,而是繼續執行。等到`b()`運行結束,可能`a()`早就運行結束了,`b()`所在的上下文環境已經消失了。如果`b()`或`c()`報錯,錯誤堆棧將不包括`a()`。 現在將這個例子改成`async`函數。 ~~~javascript const a = async () => { await b(); c(); }; ~~~ 上面代碼中,`b()`運行的時候,`a()`是暫停執行,上下文環境都保存著。一旦`b()`或`c()`報錯,錯誤堆棧將包括`a()`。
                  <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>

                              哎呀哎呀视频在线观看