1、什么是async函數
2、用法
2.1基本用法
3、語法
3.1返回promise對象
3.2promise狀態的變化
3.3await命令
1、什么是async函數
async函數也是異步編程的解決方案。
async函數是對是對generator函數進行了改進。
var readFile = function (fileName) { return new Promise(function (resolve, reject) { fs.readFile(fileName, function(error, data) { if (error) reject(error); resolve(data); }); }); }; var gen = function* () { var f1 = yield readFile('/etc/fstab'); var f2 = yield readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); };
后邊的gen函數,寫成async函數
var asyncReadFile = async function () { var f1 = await readFile('/etc/fstab'); var f2 = await readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); };
async函數就是將generator函數的星號(*)換成async,將yield替換成await。
async函數對generator函數進行改進,體現以下四點。
(1)內置執行器。
generator函數的執行必須依靠執行器,而async函數自帶執行器,也就是說,async函數的執行與普通函數一模一樣,只要一行。
下面代碼調用了asyncReadFile函數,然后就會自動執行,輸出最后的結果。這個完全不像generator函數,需要調用next方法,才能得到最終的結果。
var result=asyncReadFile();
(2)更好的語義
async和await,比起星號(*)和yield,語義更清楚。async表示函數中有異步操作,await表示緊跟其后的表達式需要等待結果。
(3)更廣的適用性
yield命令后面只能是Thunk函數或者promise對象,而async函數的await命令后面,可以是promise對象和原始類型的值(數值,字符串和布爾值,但這等同于同步操作)
(4)返回值是promise
async函數的返回值是promise對象,執行generator函數返回一個遍歷器對象(Iterator對象)方便多了,也就是說,async函數可以看做是多個異步操作,包裝成一個promise對象,而await命令是內部then命令的語法糖。
2、用法
2.1基本用法
async函數返回的是一個promise對象,可以使用then方法添加回調函數。當函數執行的時候,一旦遇到await就會先返回,等到異步操作完成,再接著執行函數體內后面的語句。
舉一個栗子
function timeout(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } async function asyncPrint(value, ms) { await timeout(ms); console.log(value); } asyncPrint('hello world', 5000);
上面代碼指定5秒后輸出hello world。
async函數多種使用形式
//函數聲明 async function foo() {} //函數表達式 const foo = async function () {} //對象的方法 let obj = { async foo() {} } obj.foo().then(...) //箭頭函數 const foo = async () => {}; //class方法 class Storage { constructor() { this.cachePromise = caches.open('avatars'); } async getAvatar(name) { const cache = await this.cachePromise; return cache.match(`/avatars/${name}.jpg`); } }
3、語法
async函數的語法規則總體上比較簡單,難點是錯誤處理機制。
3.1返回的promise對象
async函數返回的是promise對象。
async函數內部return語句返回值,會成為then方法回調函數的參數
async function f() { return 'hello world'; } f().then(v => console.log(v))
上面代碼中,函數f內部return 命令返回值,會被then方法回調函數接收到。輸出“hello world”。
async函數內部拋出的錯誤,會導致返回的promise對象變成reject狀態。拋出的錯誤對象會被catch方法回調函數接收到。
3.2promise對象狀態變化
async函數返回的promise對象,必須等到內部的所有的await命令后邊的promise對象執行完,才會發生狀態的改變,除非遇到return語句或者拋出錯誤。也就是說,只有async函數內部的異步操作執行完,才會執行then方法指定的回調函數。
舉個栗子
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)
上面代碼中,函數getTitle內部有三個操作:抓取網頁,取出文本,匹配頁面標題。只有三個操作全部完成,才會執行then方法里面console.log。
3.3 await命令
正常情況下,await命令后邊是一個promise對象。如果不是,會被轉成一個一個立即resolve的promise對象。
async function f() { return await 123; } f().then(v => console.log(v))
上面代碼中,await命令的參數是數值123,他被轉成promise對象,并立即resolve。
await命令后邊的promise對象如果變成reject狀態,則reject的參數會被catch方法的回調函數接收到。
舉個栗子
async function f() { await Promise.reject('出錯了'); } f() .then(v => console.log(v)) .catch(e => console.log(e))
上面代碼中,await語句前面沒有return,但是reject方法的參數依然傳入catch方法的回調函數,這里如果在wawait前面加上return,效果是一樣的。
只要一個await語句后面的promise變成了reject,那么整個async函數都會中斷執行。
async function f() { await Promise.reject('出錯了'); await Promise.resolve('hello world'); // 不會執行 }
上面代碼中,第二個await
語句是不會執行的,因為第一個await
語句狀態變成了reject
。
文章列表