參考:ECMAScript 6 入門
promise對象的特點:
- 對象的狀態(tài)不受外界影響迈勋,只能內部決定规哲。(三種狀態(tài):pending, fulfilled, rejected)
- 一旦狀態(tài)改變,就不會再變文兢。
const promise = new Promise(function(resolve, reject) {
resolve('ok');
throw new Error('test');
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// ok
- 一旦新建它就會立即執(zhí)行,無法中途取消。
- 跟傳統(tǒng)的try/catch代碼塊不同的是淌喻,如果沒有使用catch方法指定錯誤處理的回調函數,Promise 對象拋出的錯誤不會傳遞到外層代碼雀摘,即不會有任何反應裸删。(也就是說,即使promise內部有錯誤阵赠,程序也不會崩潰涯塔;想想其它的錯誤,如果不被catch住清蚀,程序就報錯中斷了)
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
- 調用resolve或reject并不會終結 Promise 的函數的執(zhí)行。
new Promise((resolve, reject) => {
resolve(1); // 最好在此處return枷邪,比如:return resolve(1);
console.log(2);
}).then(r => {
console.log(r);
});
console.log(3);
// 2
// 3
// 1
- resolve函數的參數除了正常的值以外榛搔,還可能是另一個 Promise 實例
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2
.then(result => console.log(result))
.catch(error => console.log(error))
// Error: fail
解釋:(我的理解:then方法只接受確定的狀態(tài)?)
p1是一個 Promise东揣,3 秒之后變?yōu)閞ejected践惑。p2的狀態(tài)在 1 秒之后改變,resolve方法返回的是p1嘶卧。由于p2返回的是另一個 Promise尔觉,導致p2自己的狀態(tài)無效了,由p1的狀態(tài)決定p2的狀態(tài)芥吟。所以侦铜,后面的then語句都變成針對后者(p1)。又過了 2 秒钟鸵,p1變?yōu)閞ejected泵额,導致觸發(fā)catch方法指定的回調函數。
- then方法返回的是一個新的Promise實例
getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL); // 又返回一個promise對象携添,該對象的返回結果將在下一個then中處理
}).then(function (comments) {
console.log("resolved: ", comments);
}).catch(function (err){
//該catch方法有可能捕獲第一個promise對象的錯誤嫁盲,也有可能捕獲第二個promise的錯誤
//Promise 對象的錯誤具有“冒泡”性質,會一直向后傳遞,直到被捕獲為止羞秤。也就是說缸托,錯誤總是會被下一個catch語句捕獲。
console.log("rejected: ", err);
});
promise的幾個API的介紹:
Promise.prototype.finally()
- ES2018(ES9)的標準瘾蛋,ES6中還沒有俐镐。
- 無論成功失敗都執(zhí)行的操作。
Promise.all()
- Promise.all方法的參數可以是數組哺哼,比如
Promise.all([p1, p2, p3])
- p1佩抹、p2、p3都是 Promise 實例取董,如果不是棍苹,就會先調用Promise.resolve方法,將參數轉為 Promise 實例茵汰,再進一步處理枢里。
- 參數也可以是具有 Iterator 接口的對象,且返回的每個成員都是 Promise 實例蹂午。
- p1, p2, p3都成功時all方法才成功栏豺,只要有一個失敗,all方法就失敗豆胸。
Promise.race()
- 參數要求同
Promise.all()
- p1, p2, p3誰先執(zhí)行完有結果奥洼,race 的 then(或catch)方法就執(zhí)行誰的,這就體現出了賽跑的特點晚胡。
Promise. resolve()
- 將現有對象轉為 Promise 對象
- 可以接受什么參數呢溉卓?
1)如果參數是 Promise 實例,那么Promise.resolve將不做任何修改搬泥、原封不動地返回這個實例。
2)如果參數是一個thenable對象伏尼。thenable對象指的是具有then方法的對象忿檩,比如下面這個對象。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
3)參數為一般的對象爆阶,或根本不是對象燥透。作為返回值返回。(如果參數為空辨图,可以認為返回undefined)
const p = Promise.resolve('Hello');
p.then(function (s){
console.log(s)
});
// Hello
Promise. reject()
- 與
Promise. resolve()
的不同:
Promise.reject()方法的參數班套,會原封不動地作為reject的理由,變成后續(xù)方法的參數
const thenable = {
then(resolve, reject) {
reject('出錯了');
}
};
Promise.reject(thenable)
.catch(e => {
console.log(e === thenable)
})
// true
Promise.try()
作用:將同步異步方法統(tǒng)一處理故河,可以更好地管理異常吱韭。
function getUsername(userId) {
return database.users.get({id: userId})
.then(function(user) {
return user.name;
});
}
上面代碼中,database.users.get()返回一個 Promise 對象鱼的,如果拋出異步錯誤理盆,可以用catch方法捕獲痘煤,就像下面這樣寫。
database.users.get({id: userId})
.then(...)
.catch(...)
但是database.users.get()可能還會拋出同步錯誤(比如數據庫連接錯誤猿规,具體要看實現方法)衷快,這時你就不得不用try...catch去捕獲。
try {
database.users.get({id: userId})
.then(...)
.catch(...)
} catch (e) {
// ...
}
上面這樣的寫法就很笨拙了姨俩,這時就可以統(tǒng)一用promise.catch()捕獲所有同步和異步的錯誤蘸拔。
Promise.try(() => database.users.get({id: userId}))
.then(...)
.catch(...)