Promise 在 JavaScript 中很早就有各類的開源實現,ES6 將其歸入了官方標準,提供了原生 api 支持,使用更加便捷。javascript
Promise 是一個對象,它用來標識 JavaScript 中異步操做的狀態(pending, resolve, reject)及結果(data)。java
從控制檯打印出來一個Promise 對象來看下
ajax
var p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('res.data');
}, 3000);
});
p.then((val) => {
console.log(val);
// 'res.data'
});
console.log(p);
// [object Promise]
Promise.resolve()方法能夠將現有對象轉爲Promise 對象。api
var p = Promise.resolve($.ajax('/something.data'));
p.then((val) => {console.log(val)});
它等價於
var p = new Promise(resolve => {
resolve($.ajax('/something.data'))
});
p.then((val) => {console.log(val)});
此方法和Promise.resolve()方法相似,除了rejecet 表明狀態爲 Rejected,很少說。數組
用於將多個Promise 實例包裝成一個新的 Promise實例,參數爲一組 Promise 實例組成的數組。promise
var p = Promise.all([p1,p2,p3]);
當 p1, p2, p3 狀態都 Resolved 的時候,p 的狀態纔會 Resolved;只要有一個實例 Rejected ,此時第一個被 Rejected 的實例的返回值就會傳遞給 P 的回調函數。app
應用場景:假設有一個接口,須要其它兩個接口的數據做爲參數,此時就要等那兩個接口完成後才能執行請求。異步
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'P1');
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'P2');
});
// 同時執行p1和p2,並在它們都完成後執行then:
Promise.all([p1, p2]).then((results) => {
console.log(results); // 得到一個Array: ['P1', 'P2']
});
和Promise.all 相似,區別是 Promise.race() 只要監聽到其中某一個實例改變狀態,它的狀態就跟着改變,並將那個改變狀態實例的返回值傳遞給回調函數。async
應用場景: 能夠經過多個異步任務來進行容錯處理,多個接口返回一樣的數據,只要有一個接口生效返回數據便可。函數
then 方法是定義在 Promise 的原型對象上的,做用是爲 Promise 實例添加狀態改變時的回調函數;
then() 返回一個新的Promise 實例,所以能夠支持鏈式寫法。
鏈式寫法的一個例子//來自廖雪峯
// 0.5秒後返回input*input的計算結果:
function multiply(input) {
return new Promise((resolve, reject) => {
console.log('calculating ' + input + ' x ' + input + '...');
setTimeout(resolve, 500, input * input);
});
}
// 0.5秒後返回input+input的計算結果:
function add(input) {
return new Promise((resolve, reject) => {
console.log('calculating ' + input + ' + ' + input + '...');
setTimeout(resolve, 500, input + input);
});
}
var p = new Promise((resolve, reject) => {
console.log('start new Promise...');
resolve(123);
});
p.then(multiply)
.then(add)
.then(multiply)
.then(add)
.then(function (result) {
console.log('Got value: ' + result);
});
catch 方法是一個語法糖,看下面代碼就明白了,用於指定發生錯誤時的回調函數。
var p = new Promise((resolve, rejecet) => {
if (...) {resolve()};
else {reject()};
})
p.then((val) => {
console.log('resolve:', val);
}).catch((err) => console.log('reject:', err));
// 等同於
p.then((data) => {
console.log(data);
}, (err) => {
console.log(err);
})
// 後一種寫法更好,語義更清晰,第一種方法在第一個函數裏面出錯的話時在第二個函數裏監聽不到變化的。
實際開發中,常常遇到一種狀況:不知道或者不想區分,函數 f 是同步函數仍是異步操做,可是想用 Promise 來處理它。由於這樣就能夠無論f是否包含異步操做,都用 then 方法指定下一步流程,用 catch 方法處理 f 拋出的錯誤。
const f = () => console.log('now');
Promise.resolve().then(f);
console.log('next');
// next
// now
const f = () => console.log('now');
(
() => new Promise(
resolve => resolve(f())
)
)();
console.log('next');
// now
// next
const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next
兩個特色
感覺: