Promise和Async/Await用法整理

1.Promise

1.簡介

Promise,簡單來說就是一個容器,里面保存著某個未來才會結(jié)束的時間(通常是一個異步操作的結(jié)果)

Promise對象的基本語法:

new Promise((resolve,reject) => {
    //.....
});

從語法上來說,Promise是一個對象,從它可以獲取異步操作的消息。

基本語法:

let p = new Promise((resolve,reject) => {
    //...
    resolve('success')
});

p.then(result => {
    console.log(result);//success
});

Promise對象特點和三個狀態(tài):


這里寫圖片描述

例如:

let p = new Promise((resolve,reject) => {
    //...
    resolve('success');
    console.log('after resolve');
    reject('error');
});

p.then(result => {
    console.log(result);
});

p.catch(result => {
    console.log(result);
})

運行結(jié)果:
after resolve
success

resolve下面的語句其實是可以執(zhí)行的,那么為什么reject的狀態(tài)信息在下面沒有接受到呢?這就是因為Promise對象的特點:狀態(tài)的凝固。new出一個Promise對象時,這個對象的起始狀態(tài)就是Pending狀態(tài),在根據(jù)resolve或reject返回Fulfilled狀態(tài)/Rejected狀態(tài)。

2.

這里寫圖片描述

Then分別接受resolve和reject的信息,有三種參數(shù)形式,第三種比較“怪異”,只用來接收做reject處理。

eg:

let p = new Promise((resolve,reject) => {
    //...
    let random = Math.random();//小于1大于0
    if(random > 0.4) {
        resolve('random > 0.4');
    }else {
        reject('random <= 0.4');
    }
});

p.then(result => {
    console.log('resolve',result);
}, result => {
    console.log('reject',result);
});


3.鏈?zhǔn)秸{(diào)用

我們來執(zhí)行一段代碼:

let p = new Promise((resolve,reject) => {
    reject('reject');
});

let resultP = p.then(null,result => {
    console.log(result);
});

console.log(resultP);

結(jié)果:
Promise { <pending> }
reject

js的執(zhí)行順序就是這樣,同步->異步->回調(diào),在同步執(zhí)行的時候,Promise對象還處于pending的狀態(tài),也說明了這個then返回的是一個Promise對象。

而且必須在then里面給一個返回值,才能繼續(xù)調(diào)用,否則undefined。
eg:

let p = new Promise((resolve,reject) => {
    reject('error');
});

let resultP = p.then(null,result => {
    console.log(result);
    return 123;
});

// console.log(resultP);
resultP.then(tmp => {
    console.log(tmp);
})

結(jié)果:
error
123

4.catch

這里寫圖片描述

eg:

let p = new Promise((resolve,reject) => {
    reject('error');
});

p.catch(result => {
    console.log(result);
})

那這個catch的返回值是什么呢:
和上面then是一樣的。

5.Promise.resolve()

這里寫圖片描述

傳一個普通的對象:

// let p1 =Promise.resolve(123);
let p1 =Promise.resolve({name:'xixi',age:'xxxx'});

p1.then(result => {
    console.log(result);
});

如果是Promise對象呢,直接返回

let p = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve('success');
    },500);
});

let pp = Promise.resolve(p);

pp.then(result => {
    console.log(result);
});

console.log(pp == p);

結(jié)果:
true
success

6.Promise.reject()

這里寫圖片描述

eg:

let p = Promise.reject(123);

console.log(p);

p.then(result => {
    console.log(result);
}).catch(result => {
    console.log('catch',result);
})

結(jié)果:
Promise { <rejected> 123 }
catch 123

7.Promise.all()

這里寫圖片描述

eg:

let p1 = Promise.resolve(123);
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('success');


Promise.all([p1,p2,p3]).then(result => {
    console.log(result);
})

結(jié)果:
[ 123, 'hello', 'success' ]

成功之后就是數(shù)組類型,當(dāng)所有狀態(tài)都是成功狀態(tài)才返回數(shù)組,只要其中有一個的對象是reject的,就返回reject的狀態(tài)值。
eg:

let p1 = Promise.resolve(123);
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('success');
let p4 = Promise.reject('error');

// Promise.all([p1,p2,p3]).then(result => {
//     console.log(result);
// });

Promise.all([p1,p2,p4]).then(result => {
    console.log(result);
}).catch(result => {
    console.log(result);
});

結(jié)果:
error

又一個eg:

//用sleep來模仿瀏覽器的AJAX請求
function sleep(wait) {
    return new Promise((res,rej) => {
        setTimeout(() => {
            res(wait);
        },wait);
    });
}

let p1 = sleep(500);
let p2 = sleep(500);
let p3 = sleep(1000);

Promise.all([p1,p2,p3]).then(result => {
    console.log(result);
    //.....
    //loading
});

8.Promise.race

這里寫圖片描述

和all同樣接受多個對象,不同的是,race()接受的對象中,哪個對象返回的快就返回哪個對象,就如race直譯的賽跑這樣。如果對象其中有reject狀態(tài)的,必須catch捕捉到,如果返回的夠快,就返回這個狀態(tài)。race最終返回的只有一個值。
eg:

//用sleep來模仿瀏覽器的AJAX請求
function sleep(wait) {
    return new Promise((res,rej) => {
        setTimeout(() => {
            res(wait);
        },wait);
    });
}

let p1 = sleep(500);
let p0 = sleep(2000);

Promise.race([p1,p0]).then(result => {
    console.log(result);
});

let p2 = new Promise((resolve,reject) => {
    setTimeout(()=>{
        reject('error');
    },1000);
});

Promise.race([p0,p2]).then(result => {
    console.log(result);
}).catch(result => {
    console.log(result);
});

500
error

9.異常處理

這里寫圖片描述

為什么說安靜,一個例子,Pormise內(nèi)部的錯誤外界用try-catch捕捉不到
eg:

try {
    let p = new Promise((resolve, reject) => {
        throw new Error("I'm error");
        // reject(new Error("I'm Error"));
    });
}catch(e) {
    console.log('catch',e);
}

結(jié)果什么都沒打印。
但是拋出的錯誤可以通過catch來捕捉:

// try {
    let p = new Promise((resolve, reject) => {
        throw new Error("I'm error");
        // reject(new Error("I'm Error"));
    });
// }catch(e) {
//     console.log('catch',e);
// }


p.catch(result => {
    console.log(result);
});


這樣就捕捉到錯誤。所以:


這里寫圖片描述

2.Async-Await

1.簡介:

這里寫圖片描述
這里寫圖片描述

async和await在干什么,async用于申明一個function是異步的,而await可以認(rèn)為是async wait的簡寫,等待一個異步方法執(zhí)行完成。

2.基本語法

這里寫圖片描述

在Chrome里申明這樣一個函數(shù),可以在控制臺看到返回的其實就是一個Promise對象。
擴展需要了解的就是Chrome現(xiàn)在也支持asyncFunction,可以在Chrome控制臺測試:
console.log(async function(){}.constructor);
? AsyncFunction() { [native code] }

3.規(guī)則

這里寫圖片描述

如圖,await放在普通函數(shù)里是會報錯的。

這里寫圖片描述

eg:

async function demo() {
    let result = await Promise.resolve(123);
    console.log(result);
}
demo();

4.應(yīng)用

Promise雖然一方面解決了callback的回調(diào)地獄,但是相對的把回調(diào)“縱向發(fā)展”了,形成了一個回調(diào)鏈。eg:

function sleep(wait) {
    return new Promise((res,rej) => {
        setTimeout(() => {
            res(wait);
        },wait);
    });
}

/*
let p1 = sleep(100);
let p2 = sleep(200);
let p =*/

sleep(100).then(result => {
    return sleep(result + 100);
}).then(result02 => {
    return sleep(result02 + 100);
}).then(result03 => {
    console.log(result03);
})

控制臺:
300

后面的結(jié)果都是依賴前面的結(jié)果。
改成async/await寫法就是:

async function demo() {
    let result01 = await sleep(100);
    //上一個await執(zhí)行之后才會執(zhí)行下一句
    let result02 = await sleep(result01 + 100);
    let result03 = await sleep(result02 + 100);
    // console.log(result03);
    return result03;
}

demo().then(result => {
    console.log(result);
});

因為async返回的也是promise對象,所以用then接受就行了。
結(jié)果:
300
需要注意的就是await是強制把異步變成了同步,這一句代碼執(zhí)行完,才會執(zhí)行下一句。

5.錯誤處理

這里寫圖片描述

如果是reject狀態(tài),可以用try-catch捕捉
eg:

let p = new Promise((resolve,reject) => {
    setTimeout(() => {
        reject('error');
    },1000);
});

async function demo(params) {
    try {
        let result = await p;
    }catch(e) {
        console.log(e);
    }
}

demo();

結(jié)果:
error
這是基本的錯誤處理,但是當(dāng)內(nèi)部出現(xiàn)一些錯誤時,和上面Promise有點類似,demo()函數(shù)不會報錯,還是需要catch回調(diào)捕捉。這就是內(nèi)部的錯誤被“靜默”處理了。

let p = new Promise((resolve,reject) => {
    setTimeout(() => {
        reject('error');
    },1000);
});

async function demo(params) {
    // try {
        let result = name;
    // }catch(e) {
    //     console.log(e);
    // }
}

demo().catch((err) => {
    console.log(err);
})

6.注意你的并行執(zhí)行和循環(huán)

比如上面的例子:


這里寫圖片描述

如果這三個是你想異步發(fā)出的AJAX請求,在這段代碼里其實是同步的,第一個發(fā)出去才會發(fā)第二個,所以async/await需要謹(jǐn)慎使用。

這里寫圖片描述

現(xiàn)在有一些forEach或者map的循環(huán)里,比如在forEach里使用await,這時候的上下文就變成了array,而不是async function,就會報錯。這時候你就要想到是什么錯誤。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 異步編程對JavaScript語言太重要。Javascript語言的執(zhí)行環(huán)境是“單線程”的,如果沒有異步編程,根本...
    呼呼哥閱讀 7,399評論 5 22
  • 簡單介紹下這幾個的關(guān)系為方便起見 用以下代碼為例簡單介紹下這幾個東西的關(guān)系, async 在函數(shù)聲明前使用asyn...
    _我和你一樣閱讀 21,476評論 1 24
  • Promise 對象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,823評論 1 56
  • Promiese 簡單說就是一個容器,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果,語法上說,Pr...
    雨飛飛雨閱讀 3,484評論 0 19
  • 相對于回調(diào)函數(shù)來說,Promise是一種相對優(yōu)雅的選擇。那么有沒有更好的方案呢?答案就是async/await。優(yōu)...
    松哥888閱讀 47,834評論 8 36

友情鏈接更多精彩內(nèi)容