同步 & 非同步(4) - async & await


Posted by TempuraEngineer on 2022-07-09

目錄


async & await

async、await是generator + Promise的語法糖。因為不必再使用Promise chaining,更加提升非同步函式的可讀性

async

  • 帶有async 關鍵字的function非await的部分事實上還是同步

    async function bar(){
      console.log('bar');
    }
    
    function foo(){
      console.log('foo');
    }
    
    bar();
    foo();
    
    // bar
    // foo
    
  • 不管是否使用await,async function內的動作都會返回一個Promise物件

    function wait(ms){
      return new Promise(r => {
        setTimeout(r, ms);
      })
    }
    
    async function foo(){
      return 'foo'; // [[Prototype]]: Promise
                    // [[PromiseState]]: "fulfilled"
                    // [[PromiseResult]]: "foo"
    }
    
    async function bar(){
      await wait(500);
      return 'bar'; // [[Prototype]]: Promise
                    // [[PromiseState]]: "fulfilled"
                    // [[PromiseResult]]: "bar"
    }
    


await

  • await 關鍵字可以讓執行暫停,直到Promise被完成

    The await keyword is for making the JavaScript function execution wait until a promise is settled

    async function bar(){
      console.log('bar');
    
      // 執行到await就暫停,先去執行同步函式foo
      await fetch('https://api.github.com/orgs/tailwindcss')
      .then((d) => d.json())
      .then(d => {
        console.log(d);
      })
    
      console.log('barr');
    }
    
    function foo(){
      console.log('foo');
    }
    
    bar();
    foo();
    
    // bar
    // foo
    // {login: 'tailwindcss', id: 30317862, node_id: 'MDEyOk9yZ2FuaXphdGlvbjMwMzE3ODYy', url: 'https://api.github.com/orgs/tailwindcss', repos_url: 'https://api.github.com/orgs/tailwindcss/repos', …}
    // barr
    
  • 只能放在async function裡

    function foo(){
      await fetch('https://api.github.com/orgs/bootstrapvue')
      .then(d => d.json())
      .then(d => console.log(d))
    }
    
    // VM1289:2 Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules
    
  • 迴圈執行非同步函式

    用迴圈執行非同步函式,且想要迴圈完成後再執行下一個指令時,可能會想這樣寫,但這樣會先執行console.log('done')(因為是同步)

      const urlArray = ['https://api.github.com/orgs/bootstrapvue', 'https://api.github.com/orgs/tailwindcss'];
    
      async function foo(arr){
        arr.forEach(async i => {
          await fetch(i)
          .then(d => d.json())
          .then(d => console.log(d))
        })
    
        console.log('done');
      }
    
      foo(urlArray);
    
      // done
      // {login: 'tailwindcss', id: 30317862, node_id: 'MDEyOk9yZ2FuaXphdGlvbjMwMzE3ODYy', url: 'https://api.github.com/orgs/tailwindcss', repos_url: 'https://api.github.com/orgs/tailwindcss/repos', …}
      // {login: 'nodejs', id: 9950313, node_id: 'MDEyOk9yZ2FuaXphdGlvbjk5NTAzMTM=', url: 'https://api.github.com/orgs/nodejs', repos_url: 'https://api.github.com/orgs/nodejs/repos', …}
    

    使用for await...of可以達到類似同步迭代的效果,但一樣只能用於async function裡

    The for await...of statement creates a loop iterating over async iterable objects as well as on sync iterables, including: built-in String, Array, Array-like objects (e.g., arguments or NodeList), TypedArray, Map, Set, and user-defined async/sync iterables.

    It invokes a custom iteration hook with statements to be executed for the value of each distinct property of the object. This statement can only be used inside an async function.

    const urlArray = ['https://api.github.com/orgs/bootstrapvue', 'https://api.github.com/orgs/tailwindcss'];
    
    async function foo(arr){
      for await(let i of arr){
        await fetch(i)
        .then(d => d.json())
        .then(d => console.log(d))
      }
    
      console.log('done');
    }
    
    foo(urlArray);
    
    // {login: 'tailwindcss', id: 30317862, node_id: 'MDEyOk9yZ2FuaXphdGlvbjMwMzE3ODYy', url: 'https://api.github.com/orgs/tailwindcss', repos_url: 'https://api.github.com/orgs/tailwindcss/repos', …}
    // {login: 'nodejs', id: 9950313, node_id: 'MDEyOk9yZ2FuaXphdGlvbjk5NTAzMTM=', url: 'https://api.github.com/orgs/nodejs', repos_url: 'https://api.github.com/orgs/nodejs/repos', …}
    // done
    
  • serial operation & parallel operation

      function foo(packageName){
        return fetch(`https://api.github.com/orgs/${packageName}`)
        .then(d => {
          console.log(`${packageName} done.`)
          return d.json();
        })
      }
    
      // 依序
      async function series() {
        return [await foo('vuejs'), await foo('nodejs'), await foo('tailwindcss')];
      }     
    
      // 平行
      async function parallel() {
        const vueInfo = foo('vuejs');
        const tailwindInfo = foo('tailwindcss');
        const nodeInfo = foo('nodejs'); // 先把Promise建立起來
    
        return [await vueInfo, await tailwindInfo, await nodeInfo];
      }    
    
      await series();
      await parallel();
    


🖊名詞解釋

名詞 解釋 其他
settled Promise已被完成,狀態不會再改變了


📖參考資料

async functions - make promise friendly
JavaScript async and await - in plain English, please

現代化的 JavaScript 併發 - Async Functions

MDN - for await...of

阮一峰 - async
阮一峰 - await


#Async #Await







Related Posts

ES6(Default Parameters、箭頭函式、Import 與 Export、Babel)

ES6(Default Parameters、箭頭函式、Import 與 Export、Babel)

Git 版本控制入門(2)- branch

Git 版本控制入門(2)- branch

 Laravel 入門:認識 Migration

Laravel 入門:認識 Migration


Comments