異步函數,async,await那些你忽略的進程

異步函數

  • 異步函數,也稱爲async/await(語法關鍵字),是es6promise在JS函數中的應用,這個特性從行爲和語法上都加強了JS,讓以同步方式寫的代碼可以異步執行

例子1:這個期約在超時以後會解決爲一個值,若是程序中其餘代碼要訪問這個值,則須要一個解決處理函數es6

let p = new Promise((resolve, reject) => 
setTimeout(resolve, 1000, 3)); p.then((x) => console.log(x)); // 3 複製代碼

async

  • async關鍵字用於聲明異步函數,這個關鍵之能夠用在函數聲明,函數表達式,箭頭函數和方法上,這個關鍵字可讓函數具備異步的特性,但整體上代碼任然是同步求值得,在參數和閉包方面,異步函數任然具備普通JS函數的正常行爲
async function foo() {
 console.log(1);  return 3;  } // 給返回的期約添加一個解決處理程序  foo().then(console.log);  console.log(4);  console.log(5); // 1 ,4 ,5 , 3 複製代碼

小結:在異步函數若是使用了return返回了值,這個值會被promise.resolve()包裝成一個期約函數,異步函數始終返回期約對象,在函數外部調用能夠獲得他返回的期約promise

  • 異步函數的返回值期待一個thenable接口的對象,這個對象能夠提供給then()的處理程序解包,若是不是,就會被當作已經解決期約結果
// 返回一個沒有實現thenable接口的對象
 async function bar() {  return ['bar'];  }  bar().then(console.log); // ['bar'] // 返回一個實現了thenable接口的非期約對象  async function baz() {  const thenable = {  then(callback) {  callback('baz');  }  };  return thenable;  }  baz().then(console.log); // baz  // 返回一個期約  async function qux() {  return Promise.resolve('qux');  }  qux().then(console.log); // qux 複製代碼

小結:異步函數返回值,含thenable則提供then的處理程序解包,不然把返回值當期約處理結果,可是要注意,拒絕期約的錯誤不會被異步函數捕獲瀏覽器

async function foo() {
 console.log(1);  Promise.reject(3);  }  // Attach a rejected handler to the returned promise   foo().catch(console.log);  console.log(2);  // 1  // 2   // Uncaught (in promise): 3 複製代碼

await

  • 由於異步函數主要針對不會立刻完成的任務,因此須要一種暫停和恢復執行的能力,使用await能夠暫停異步函數的代碼執行,等待期約解決
//異步寫法
 let p = new Promise((resolve, reject) =>  setTimeout(resolve, 1000, 3));  p.then((x) => console.log(x)); // 3 //async寫法  async function foo() {  let p = new Promise((resolve, reject) =>  setTimeout(resolve, 1000, 3));  console.log(await p);  } 複製代碼

小結:await關鍵字會暫停執行異步函數後面的代碼,讓出JS運行時的執行線程,這個行爲和生成器中的yield關鍵字同樣,await關鍵字一樣是嘗試解包對象的值,而後將這個值傳達給表達式,,再異步恢復異步函數的執行markdown

接下來看一個涉及中止與恢復執行的例子:這個例子很是有意思,雖然如今你看不到這種效果,可是能更直白幫你理解await

  • 爲了更好的理解這個例子,首先要知道這幾個問題閉包

    • await的地方,等於局部暫停,等待返回值,繼續其餘線程異步

    • 一樣的await按照前後順序從上往下async

    • 當await有多個進程之後,會按照多列順序執行函數

      例子1:oop

async function foo() {
 console.log(await Promise.resolve('foo'));  }  async function bar() {  console.log(await 'bar');  }  async function baz() {  console.log('baz');  }  foo();  bar();  baz();  // baz // bar // foo 複製代碼

小結:正常狀況是這個順序,可是你在瀏覽器跑的時候,結果bar和foo的值會調換位子ui

首先咱們說一下執行原理:

  • foo()調用時,foo在消息隊列添加兩列進程,第一列等待返回值,第二列拿到返回值後執行的進程,
  • 而後繼續bar()這時候在消息隊列第一列添加一個進程,這時候執行baz,直接打印出‘baz',
  • 而後開始消息隊列進程,foo第一列期約得出結果拿到返回值,而後繼續bar的消息隊列第一列進程,這時候打印出'bar',這時候消息隊列第一列進程所有執行完畢,
  • 進入第二列,foo用第一列進程拿到的返回值執行進程,打印foo,

其次咱們說一下爲何瀏覽器的結果不是這樣:1TC39 對 await 後面是期約的狀況如何處理作過一次修改。修改後,本例中的 foo()裏的await Promise.resolve(’foo‘)只會生成一個異步任務。因此他執行的時候沒有兩列,只有一列,因此會按await順序排列

  • 按照上面理解,咱們來看最終的一個例子
async function foo() {
 console.log(2);  console.log(await Promise.resolve(8));  console.log(9);  }  async function bar() {  console.log(4);  console.log(await 6);  console.log(7);  }  console.log(1);  foo();  console.log(3);  bar();  console.log(5);  // 1 // 2 // 3 // 4 // 5 //8 // 9 // 6// 7 複製代碼

小結:上面顯示的最新修改事後的結果,按照原結果進程應該是

  • 打印1,運行foo,打印2,消息隊列加入兩列,打印3,運行bar,打印4,消息隊列加一列進程,打印5,開始執行消息隊列第一行,foo拿到返回值,bar打印6,而後打印7,回到foo第二列,打印結果8,再打印9

本文使用 mdnice 排版

相關文章
相關標籤/搜索