Promise
異步編程的一種解決方案。是一個對象,從它可以獲取異步操作的信息。三種狀態(tài):pending,fulfilled,rejected。
缺點:一單建立就會立即執(zhí)行,無法中途取消;不設(shè)置回調(diào)函數(shù),Promise內(nèi)部破除的錯誤不會反應(yīng)到外部。
1:常見用法
//構(gòu)造函數(shù)
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 異步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
//使用返回的狀態(tài)
promise.then(function(value) {
// success
}, function(error) {
// failure
});
//執(zhí)行順序
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('resolved');
});
console.log('Hi!');
執(zhí)行結(jié)果
Promise;
Hi!
resolved
注:Promise 新建后就會立即執(zhí)行。所以先執(zhí)行 console.log('Promise');
new Promise((resolve, reject) => {
resolve(1);
console.log(2);
}).then(r => {
console.log(r);
});
// 2
// 1
注:般來說,調(diào)用resolve或reject以后,Promise 的使命就完成了,后繼操作應(yīng)該放到then方法里面,而不應(yīng)該直接寫在resolve或reject的后面。所以,最好在它們前面加上return語句,這樣就不會有意外。
new Promise((resolve, reject) => {
return resolve(1);
// 后面的語句不會執(zhí)行
console.log(2);
})
//1
Promise.prototype.then()
Promise 實例具有then方法,也就是說,then方法是定義在原型對象Promise.prototype上的。then方法的第一個參數(shù)是resolved狀態(tài)的回調(diào)函數(shù),第二個參數(shù)是rejected狀態(tài)的回調(diào)函數(shù),它們都是可選的。then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。因此可以采用鏈?zhǔn)綄懛ǎ磘hen方法后面再調(diào)用另一個then方法。
const getJSON = (url)=> {
const promise = new Promise(function(resolve, reject){
const client = new XMLHttpRequest();
client.open("GET", url);
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出錯了', error);
});
getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 處理 getJSON 和 前一個回調(diào)函數(shù)運行時發(fā)生的錯誤
console.log('發(fā)生錯誤!', error);
});
//下面兩個方法都能正確剖出錯誤
p.then((val) => console.log('fulfilled:', val))
.catch((err) => console.log('rejected', err));
p.then((val) => console.log('fulfilled:', val))
.then(null, (err) => console.log("rejected:", err));
//建議寫法
promise.then(function(data) {
// success
}).catch(function(err) {
// error
});
Promise 內(nèi)部的錯誤不會影響到 Promise 外部的代碼,通俗的說法就是“Promise 會吃掉錯誤”。
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// 下面一行會報錯,因為x沒有聲明
resolve(x + 2);
});
};
someAsyncThing().then(function() {
console.log('everything is great');
});
setTimeout(() => { console.log(123) }, 2000);
// Uncaught (in promise) ReferenceError: x is not defined
// 123
Promise.prototype.finally()
finally()方法用于指定不管 Promise 對象最后狀態(tài)如何,都會執(zhí)行的操作。該方法是 ES2018 引入標(biāo)準(zhǔn)的。
finally方法的回調(diào)函數(shù)不接受任何參數(shù),這意味著沒有辦法知道,前面的 Promise 狀態(tài)到底是fulfilled還是rejected。這表明,finally方法里面的操作,應(yīng)該是與狀態(tài)無關(guān)的,不依賴于 Promise 的執(zhí)行結(jié)果。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
//例子
server.listen(port)
.then(function () {
// ...
})
.finally(server.stop);
Promise.all()
Promise.all()方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例。
const p = Promise.all([p1, p2, p3]);
Promise.allSettled()
有時候,我們希望等到一組異步操作都結(jié)束了,不管每一個操作是成功還是失敗,再進行下一步操作。但是,現(xiàn)有的 Promise 方法很難實現(xiàn)這個要求。
為了解決這個問題,ES2020 引入了Promise.allSettled()方法,用來確定一組異步操作是否都結(jié)束了(不管成功或失?。K?,它的名字叫做”Settled“,包含了”fulfilled“和”rejected“兩種情況。
Promise.any()
ES2021 引入了Promise.any()方法。該方法接受一組 Promise 實例作為參數(shù),包裝成一個新的 Promise 實例返回。
只要參數(shù)實例有一個變成fulfilled狀態(tài),包裝實例就會變成fulfilled狀態(tài);如果所有參數(shù)實例都變成rejected狀態(tài),包裝實例就會變成rejected狀態(tài)。
Promise.any()跟Promise.race()方法很像,只有一點不同,就是Promise.any()不會因為某個 Promise 變成rejected狀態(tài)而結(jié)束,必須等到所有參數(shù) Promise 變成rejected狀態(tài)才會結(jié)束。
Promise.any([
fetch('https://v8.dev/').then(() => 'home'),
fetch('https://v8.dev/blog').then(() => 'blog'),
fetch('https://v8.dev/docs').then(() => 'docs')
]).then((first) => { // 只要有一個 fetch() 請求成功
console.log(first);
}).catch((error) => { // 所有三個 fetch() 全部請求失敗
console.log(error);
});