Promise 概述
關於Promise
-
Promise
例項一旦被建立就會被執行 -
Promise
過程分為兩個分支:pending=>resolved
和pending=>rejected
-
Promise
狀態改變後,依然會執行之後的程式碼:
const warnDemo = ctx => {
const promise = new Promise(resolve => {
resolve(ctx);
console.log("After resolved, but Run"); // 依然會執行這個語句
});
return promise;
};
warnDemo("ctx").then(ctx => console.log(`This is ${ctx}`));
then
方法
在Console
鍵入以下內容:
let t = new Promise(()=>{});
t.__proto__
可以看到,then
方法是定義在原型物件Promise.prototype
上的。
then
方法的第一個引數是resolved
狀態的回撥函式,第二個引數(可選)是rejected
狀態的回撥函式。
寫法
function func(args) {
// 必須返回一個Promise例項
return new Promise((resolve,reject)=>{
if(...){
resolve(...) // 傳入resolve函式的引數
} else {
let err = new Error(...)
reject(err) // reject引數必須是Error物件
}
})
}
func(ARGS).then(()=>{
// resolve 函式
},()=>{
// reject 函式
})
連續呼叫then
因為then
方法返回另一個Promise
物件。當這個物件狀態發生改變,就會分別呼叫resolve
和reject
寫法如下:
func(ARGS).then(()=>{
...
}).then(
()=>{ ... },
() => { ... }
)
例項
function helloWorld(ready) {
return new Promise((resolve,reject)=>{
if (ready){
resolve("Right")
} else {
let error = new Error("arg is false")
reject(error) // 傳入Error物件
}
})
}
helloWorld(false).then((msg)=>{ // true:helloWorld的引數
// 引數msg:在上面的Promise物件中傳入了
console.log(msg)
},(error)=>{
console.log(error.message)
})
catch
方法
等同於 .then(null, rejection)
。另外,then
方法指定的回撥函式執行中的錯誤,也會被catch
捕獲。
所以,之前的寫法可以改為:
function func(args) {
// 必須返回一個Promise例項
const promise = new Promise((resolve,reject)=>{
if(...){
resolve(...)
} else {
let err = new Error(...)
reject(err)
}
})
return promise
}
func(ARGS).then(()=>{
// resolve 函式
}).catch(()=>{
// reject 函式
}).then(()=>{
// 沒有錯誤就會跳過上面的catch
})...
finally
方法
指定不管
Promise
物件最後狀態如何,都會執行的操作。可以理解為then
方法的例項,即在resolve
和reject
裡面的公共操作函式
all
方法
用於將多個
Promise
例項,包裝成一個新的Promise
例項。它接收一個具有Iterator
介面的引數。其中,item
如果不是Promise
物件,會自動呼叫Promise.resolve
方法
以下程式碼:
const p = Promise.all([p1, p2, p3]); // p是新包裝好的一個Promise物件
對於Promise.all()
包裝的Promise
物件,只有例項的狀態都變成fulfilled
。
可以用來運算元據庫:
const databasePromise = connectDatabase();
const booksPromise = databasePromise
.then(findAllBooks);
const userPromise = databasePromise
.then(getCurrentUser);
Promise.all([
booksPromise,
userPromise
])
.then(([books, user]) => pickTopRecommentations(books, user));
或者其中有一個變為rejected
,才會呼叫Promise.all
方法後面的回撥函式。而對於每個promise
物件,一旦它被自己定義catch
方法捕獲異常,那麼狀態就會更新為resolved
而不是rejected
。
'use strict'
const p1 = new Promise((resolve, reject) => {
resolve('hello');
}).then(
result => result
).catch(
e => e
);
const p2 = new Promise((resolve, reject) => {
throw new Error("p2 error")
}).then(
result => result
).catch(
// 如果註釋掉 catch,進入情況2
// 否則,情況1
e => e.message
);
Promise.all([p1, p2]).then(
result => console.log(result) // 情況1
).catch(
e => console.log("error in all") // 情況2
);
race方法
和
all
方法類似,Promise.race
方法同樣是將多個Promise
例項,包裝成一個新的Promise
例項。而且只要有一個狀態被改變,那麼新的Promise
狀態會立即改變
也是來自阮一峰大大的例子,如果5秒內無法fetech
,那麼p
狀態就會變為rejected
。
const p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
]);
p.then(response => console.log(response));
p.catch(error => console.log(error));
重要性質
狀態只改變一次
Promise
的狀態一旦改變,就永久保持該狀態,不會再變了。
下面程式碼中,Promise
物件resolved
後,狀態就無法再變成rejected
了。
'use strict'
const promise = new Promise((resolve,reject)=>{
resolve('ok') // 狀態變成 resolved
throw new Error("test") // Promise 的狀態一旦改變,就永久保持該狀態
})
promise.then((val)=>{
console.log(val)
}).catch((error)=>{
console.log(error.message) // 所以,無法捕獲錯誤
})
錯誤冒泡
Promise
物件的錯誤具有“冒泡”性質,會一直向後傳遞,直到被捕獲為止。也就是說,錯誤總是會被下一個catch
語句捕獲
"吃掉錯誤"機制
Promise
會吃掉內部的錯誤,並不影響外部程式碼的執行。所以需要catch
,以防丟掉錯誤資訊。
阮一峰大大給出的demo:
'use strict'
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);
還有如下demo
someAsyncThing().then(function() {
return someOtherAsyncThing();
}).catch(function(error) {
console.log('oh no', error);
// 下面一行會報錯,因為y沒有宣告
y + 2;
}).catch(function(error) {
console.log('carry on', error);
});
// oh no [ReferenceError: x is not defined]
// carry on [ReferenceError: y is not defined]
參考
- demo基本可以在阮一峰的Es6講解中找到,只是為了理解做了一些修改。
- 還有網上的一些部落格,這裡就不一一說明了
歡迎技術交流,引用請註明出處。
個人網站:godbmw.com
Github:godbmw
相關文章
- Promise和Promise的方法Promise
- promisePromise
- Promise規範以及手寫PromisePromise
- 淺談Promise之按照Promise/A+規範實現Promise類Promise
- promise專題--手寫promise03Promise
- 學習Promise && 簡易實現PromisePromise
- Promise之你看得懂的PromisePromise
- 一、promisePromise
- My PromisePromise
- Javascript — PromiseJavaScriptPromise
- Promise then() 方法Promise
- Promise初探Promise
- 深入 PromisePromise
- promise容器Promise
- Promise使用Promise
- 得到promisePromise
- Promise in ChakraPromise
- 你好,promisePromise
- promise with asyncPromise
- Promise in JavascriptPromiseJavaScript
- Promise原理講解 && 實現一個Promise物件 (遵循Promise/A+規範)Promise物件
- 基於promise /A+規範手寫promisePromise
- 手撕遵循 Promise/A+ 規範的 PromisePromise
- 如何使用Promise.race() 和 Promise.any() ?Promise
- 從手寫一個符合Promise/A+規範Promise來深入學習PromisePromise
- 概述
- 你能手寫一個Promise嗎?Yes I promise。Promise
- jquery Promise和ES6 Promise的區別jQueryPromise
- Promise進階——如何實現一個Promise庫Promise
- JavaScript 在 Promise.then 方法裡返回新的 PromiseJavaScriptPromise
- async/await 和 promise/promise.all 的示例AIPromise
- 大白話講解Promise(二)理解Promise規範Promise
- JavaScript Promise物件JavaScriptPromise物件
- Promise不是CallbackPromise
- JS promise物件JSPromise物件
- Promise基本用法Promise
- promise is a monad?Promise
- Async & generator & PromisePromise