1. 程式人生 > >js的三種異步處理

js的三種異步處理

html 運行 只需要 執行 關鍵字 logs don gen hello

Promise 對象

  • 含義: Promise是異步編程的一種解決方案,
  • 優點: 相比傳統回調函數和事件更加合理和優雅,Promise是鏈式編程(後面會詳細講述),有效的解決了令人頭痛的回調地獄問題,Promise的結果有成功和失敗兩種狀態,只有異步操作的結果,可以決定當前是哪一種狀態,外界的任何操作都無法改變這個狀態
  • 基本用法:
    //ES6 規定,Promise對象是一個構造函數,用來生成Promise實例。
    const p = new Promise(function(resolve,reject){
        if(success){
            resolve(‘成功的結果‘)
        }else{
            reject(‘失敗的結果‘)
        }
    })
    p.then(function (res) {
        // 接收resolve傳來的數據,做些什麽
        
    },function (err) {
        // 接收reject傳來的數據,做些什麽
    })
    p.catch(function (err) {
        // 接收reject傳來的數據或者捕捉到then()中的運行報錯時,做些什麽
    })
    p.finally(function(){
        // 不管什麽狀態都執行
    })
  • 常用API
    • resolve 返回異步操作成功的結果
    • reject 返回異步操作失敗的結果
    • then 執行Promise狀態是成功的操作
    • catch 執行Promise狀態是失敗的操作
    • finally 不管Promise狀態是成功或失敗都執行的操作
  • Promise.all
    • Promise.all方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。
    const p = Promise.all([p1, p2, p3])
p的狀態由p1、p2、p3決定,分成兩種情況。
(1)只有p1、p2、p3的狀態都變成fulfilled,p的狀態才會變成fulfilled,此時p1、p2、p3的返回值組成一個數組,傳遞給p的回調函數。
(2)只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。

Generator 函數

  • 含義: Generator 函數是 ES6 提供的一種異步編程解決方案,語法行為與傳統函數完全不同,
    • 基本用法:
    function* helloGenerator() {
      yield ‘hello‘;
      yield ‘Generator‘;
      return ‘over‘;
    }
    
    let hw = helloGenerator();
    hw.next()//{value:"hello",done:false}
    hw.next()//{value:"Generator",done:false}
    hw.next()//{value:"over",done:true}
    hw.next()//{value:undfined,done:true}
  • 特征:
    • 一是,function關鍵字與函數名之間有一個星號;
    • 二是,函數體內部使用yield表達式,定義不同的內部狀態;
    • 三是,通過next方法獲取每段狀態的返回結果,上面分成4次執行了Gennrator函數,第一次,獲取第一個yield函數的返回結果並暫停,done:false,代表函數內的狀態還沒有執行結束;第二次,同理;第三次,獲取return 的返回結果,done:true表示函數內的狀態已經執行完畢;第四次,函數內已經沒有可以執行的狀態,所有返回undfined,同時告訴函數內的狀態已經執行完畢;如果函數內沒有return,在第三次時返回undfined,done:true表示函數內的狀態已經執行完畢

async 函數

  • 含義: async 函數是在ES2017 標準中引入的,async使得異步操作變得更加方便,其實他就是Generator 函數的語法糖
  • 基本用法:
    function get1(){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{resolve(1)},2000)
            
        })
    }
    async function getSet(){
        const n = await get1()
        //const n = await ‘111‘
        return n
    }
    getSet().then(console.log)
  • 說明:
    • await命令只能用在async函數之中,如果用在普通函數,就會報錯。
    • await後面是一個Promise對象,如get1 return出去的Promise實例;如果不是 Promise 對象,就直接返回對應的值,如直接返回‘111‘。
      • 1、若Promise 對象, 並且其以值 x 被 fulfilled, 則返回值為 x.
      • 2、Promise 對象, 並且其以異常 e 被 rejected, 則拋出異常 e
    • async函數返回的 Promise 對象,必須等到內部所有await命令後面的 Promise 對象執行完,才會發生狀態改變,如果任何一個await語句後面的 Promise 對象變為reject狀態或遇到return,那麽整個async函數都會中斷執行。
    • 另外需要註意的是, await 在等待 Promise 對象時會導致 async function 暫停執行, 一直到 Promise 對象決議之後才會 async function 繼續執行.
    • 如果我們希望即使前一個異步操作失敗,也不要中斷後面的異步操作。這時可以將第一個await放在try...catch結構裏面,這樣不管這個異步操作是否成功,第二個await都會執行。
    async function f() {
        try {
            await Promise.reject(‘出錯了‘);
        } catch(e) {
        }
        return await Promise.resolve(‘hello world‘);
    }

    f().then(v => console.log(v))
  • 優點: 相比Generator函數,async函數有如下四點改進
    • 內置執行器: Generator 函數的執行必須靠next()進行每一次的模塊執行,async自帶執行器,只需要和普通函數一樣調用即可執行
    • **更好的語義:**async表示函數裏有異步操作,await表示緊跟在後面的表達式需要等待結果。
    • 返回值是Promise: async函數的返回值是 Promise 對象,可以用then方法指定下一步的操作;而且async函數完全可以看做多個異步函數的操作,包裝成的一個 Promise 對象,而await命令就是內部then命令的語法糖,即Promise.all()的用法
    • **更廣的適用性:**相較於Generator函數async函數的await命令後面,可以是 Promise 對象和原始類型的值(數值、字符串和布爾值,但這時會自動轉成立即 resolved 的 Promise 對象)
  • 補充
    • 多個await命令後面的異步操作,如果不存在繼發關系,最好讓它們同時觸發。
    //此處省略getFoo(), getBar()兩個函數
    
    // 寫法一
    async function getSet(){
        let [foo, bar] = await Promise.all([getFoo(), getBar()]);
        return [foo, bar]
    }

    // 寫法二
    async function getSet(){
        let fooPromise = getFoo();
        let barPromise = getBar();
        let foo = await fooPromise;
        let bar = await barPromise;
        return [foo, bar]
    }

*文章參考ECMAScript 6 入門 *

js的三種異步處理