1. 程式人生 > 其它 >ES6 async函式(超級詳細、易懂)

ES6 async函式(超級詳細、易懂)

技術標籤:ES6

下面是對 ES6 async函式的整理,希望可以幫助到有需要的小夥伴~

文章目錄

async函式是什麼

ECMAScript 2017規範引入了async函式,該函式的主要目的是簡化使用Promise非同步呼叫的操作,並對一組Promise執行某些操作。

Promise類似於結構化回撥

async、await類似於組合生成器和Promises。

await 操作符用於等待一個Promise 物件。它只能在非同步函式 async function 中使用

function resolveAfter2Seconds() {
    return new Promise(resolve => {
        setTimeout(()=>{
            resolve('resolved');
        },2000);
    })
}

async function asyncCall() {
    console.
log("calling"); // calling // 暫停當前asyncCall()函式的執行,等待Promise處理完成後再執行asyncCall()函式 var result = await resolveAfter2Seconds(); console.log(result); // resolved } asyncCall();

非同步函式宣告式

非同步函式宣告式用於定義一個返回Promise物件的非同步函式。

非同步函式是指通過事件迴圈非同步執行的函式,它會通過一個隱式的Promise返回其結果

非同步函式的語法和結構與同步函式比較像。

async
function name([param[, param[, ... param]ll) { statements }
  • name:函式名稱
  • param:要傳遞給函式的引數的名稱。
  • statements:表示函式體語句。

非同步函式表示式

步函式表示式用於在表示式中定義非同步函式。

let name = async function([param1[, param2[ .., paramN]]]) { statements }
  • name:表示函式名稱。
  • pacam:要傳遞給函式的引數的名稱。
  • statements:表示函式體語句。

非同步函式表示式與非同步函式語句宣告式的區別:

於非同步函式表示式可以省略函式名稱來建立一個匿名函式。

返回Promise物件

async函式返回一個Promise物件

async函式內部return語句返回的值,會成為then方法回撥函式的引數。

例項1:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-JPVf9Xvg-1608908797743)(es6/async1.png)]

例項2:

async function f() {
    return "hello world";
}
// f().then(v=>console.log(v)); // hello world

// 等同於
f().then(
    function (v) {
        console.log(v); // hello world
    }
)

// 上述非同步函式async function中沒有await表示式,因為非同步函式會先建立Promise物件,然後再執行

注意:

上述非同步函式async function中沒有await表示式,因為非同步函式會先建立Promise物件,然後再執行

await表示式

await表示式用於等待一個Promise物件,它只能在非同步函式中使用

[return .value] = await expression;
  • expression:一個Promise物件或者任何要等待的值。

  • return…alue

    • 如果等待的是Promise物件,返回Promise物件的處理結果(成功或失敗)。
    • 如果等待的不是Promise 物件,則返回該值本身。
function createPromise(){
    return new Promise((resolve,reject) => {
        setTimeout(() => {
            resolve("執行成功");
        },200);
    });
}


async function myAsync() {
    console.log("當前非同步函式被呼叫");
    var result = await createPromise();
    console.log("Promise物件執行的結果:" + result);
}

myAsync(); // 呼叫非同步函式

await處理錯誤

為了防止報錯,使用try…catch語句

function createPromise(){
    return new Promise((resolve,reject) => {
        setTimeout(() => {
            reject("執行失敗");
        },200);
    });
}


async function myAsync() {
    console.log("當前非同步函式被呼叫"); // 當前非同步函式被呼叫
    try {
        // 執行後會出錯的語句
        var result = await createPromise();
    } catch(e) {
        // 提示錯誤的語句
        console.log("Promise物件執行的結果:" + e); // Promise物件執行的結果:執行失敗
    }

}

myAsync(); // 呼叫非同步函式

async函式執行一組Promise

一組Promise物件的執行順序只與async函式中await的順序有關。

let promise1 = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve("one");
    },300);
});

let promise2 = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve("two");
    },200);
});

let promise3 = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve("three");
    },100);
});

async function myAsync() {
    let result1 = await promise1;
    console.log(result1);

    let result2 = await promise2;
    console.log(result2);

    let result3 = await promise3;
    console.log(result3);
}
myAsync();


// Promise物件執行的順序與設定的延遲時間沒有關係,Promise物件執行的順序只與async函式中的順序有關

注意事項

使用try…catch語句

await命令後面的Promise 物件,執行結果可能是rejected,有2種處理錯誤的方法

  1. try…catch語句
  2. Promise的catch語句

例項:

function fun() {
    return new Promise((resolve,reject) => {
        reject("執行失敗");
    })
}

// try...catch處理錯誤
async function myAsync1() {
    try {
        await fun();
    }catch (e) {
        console.log(e);
    }
}

myAsync1(); // 執行失敗

// catch處理錯誤
async function myAsync2() {
    await fun().catch(function (err) {
                    console.log(err);
    })
}

myAsync2(); // 執行失敗

多個await同時觸發

多個await表示式後面的非同步操作,如果不存在繼發關係,最好讓它們同時觸發。

let promise1 = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve("one");
    },300);
});

let promise2 = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve("two");
    },200);
});

let promise3 = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve("three");
    },100);
});

// promise1,promise2,promise3依次獨立的非同步操作
/*async function myAsync() {
    let result1 = await promise1;
    console.log(result1);

    let result2 = await promise2;
    console.log(result2);

    let result3 = await promise3;
    console.log(result3);
}
myAsync();*/

// Promise物件執行的順序與設定的延遲時間沒有關係,Promise物件執行的順序只與async函式中的順序有關

// promise1,promise2,promise3同時執行非同步操作
async function myAsync3() {
    let [result1,result2,result3] = await Promise.all([promise1,promise2,promise3]);
    console.log(result1,result2,result3)
}
myAsync3(); // one two three

promise1,promise2,promise3是3個獨立的非同步操作(即互不依賴),被寫成繼發關係一個一個的進行非同步操作是比較耗時間的,可以讓promise1,promise2,promise3同時觸發,同時進行非同步操作(同時觸發的條件:promise1,promise2,promise3按順序執行)。

await表示式的限制

await表示式只能用在async函式之中,如果用在普通函式,就會報錯。

async function f1() {
    let docs = [{},{},{}];

    // 報錯
    docs.forEach(function (doc) {
        await db.post(doc); // SyntaxError: await is only valid in async function 翻譯:SyntaxError: await只在非同步函式中有效
    })
}

Symbol

ECMAScript 6新增了第六種原始型別Symbol(符號)型別。

Symbol型別是唯一的並且是不可修改的,並且也可以用來作為Object 的 key 值。

Symbol型別的變數是通過呼叫Symbol()函式生成的:

Symbol([description])
  • description:可選的字串。Symbol的描述,可用於除錯但不能訪問Symbol本身。

注意:

由於Symbol型別是原始型別,是不能通過new Symbol()來建立物件的。

例項:

/*
    ES5 的 5種原始型別
    * string - String
    * number - Number
    * string - String
    * undefined - Undefined
    * null - Null
    ES6 新增一種原始型別
    Symbol
*/

let num = 100;  // new Number()
let str = "軟體學院"; // new String()
let boo = true;
/*
    symbol型別是ES6新增的第六種原始型別
    Symbol型別是唯一的並且是不可修
    let symbol = Symbol()
    原始型別是不能建立物件的
*/

let symbol = Symbol();
console.log(typeof symbol); // symbol 判斷原始型別必須使用typeof

let symbol2 = Symbol("xxx");
console.log(symbol2); // Symbol(xxx)
let symbol3 = Symbol(5);
console.log(symbol3); // Symbol(5)

// 修改變數的值,而不是修改型別,Symblo是不能轉為其它型別的
symbol3 = Symbol("yyy");
console.log(symbol3); // Symbol(yyy)


Symbol的注意事項

當使用Symbol值進行型別轉換時需要注意一些事情:

  • 嘗試將一個symbol值轉換為一個number值時,會丟擲一個工ypeError錯誤。
  • Object(symbol) == symnbol表示式的結果返回true。
  • 阻止從一個symbol 值隱式地建立一個新的string型別的屬性名。

Symbol的方法

  • Symbol.for()方法

    該方法會根據給定的鍵key,從symbol登錄檔中查詢指定的key。

    • 如果找到了,則返回它。
    • 如果沒有找到,新建一個與該鍵關聯的 symbol,並放入全域性symbol登錄檔中。
    Symbol.for(key);
    
    • 一個字串,作為symbol登錄檔中與某symbol關聯的鍵。

    • Symbol.for()方法與Symbol()的不同:

      • 用Symbol.for()方法建立的的symbol會被放人一個全域性symbol登錄檔中
      • 用Symbol()方法建立的的symbol不會被放人一個全域性symbol登錄檔中

    登錄檔是一個典型的鍵值對key : value集合

    舉例:

    kye - 儲存的方式

    value - 當前安裝的軟體

  • Symbol.keyFor()方法

    該方法用於獲取symbol登錄檔中與某個symbol關聯的鍵。

    Symbol.keyFor(sym);
    
    • sym:儲存在symbol登錄檔中的某個symbol.

Symbol與for…in

Symbols 在 for…in迭代中不可列舉。

Object.getOwnPropertyNames()不會返回symbol物件的屬性,但是可以使用Object.getOwnPropertySymbols()得到它們.

var obj = {};
// 如果Symbol作為物件的屬性名,屬性名是不可列舉的
obj[Symbol("a")] = "a";
obj[Symbol.for("b")] = "b";
obj["c"] = "c";
obj.d = "d";

for (var i in obj) {
    console.log(i); // c d 用Symbol作為物件的屬性名的a和b是沒有辦法被列舉的
}

end 結束啦~
在這裡插入圖片描述