文章出處

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

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜

    大師兄 發表在 痞客邦 留言(0) 人氣()