ES6中的Promise详解
Promise 在 JavaScript 中很早就有各種的開源實現(xiàn),ES6 將其納入了官方標準,提供了原生 api 支持,使用更加便捷。
定義
Promise 是一個對象,它用來標識 JavaScript 中異步操作的狀態(tài)(pending, resolve, reject)及結果(data)。
從控制臺打印出來一個Promise 對象來看下
可以看到,它是一個構造函數(shù),既有屬于自己私有的 resolve, reject, all, race等方法,也有protype 原型上的 then, catch等方法。
基本用法
- 模擬問題:3秒后請求完成,返回數(shù)據(jù)res.data
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.resolve()方法可以將現(xiàn)有對象轉為Promise 對象。
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.reject() 用法
此方法和Promise.resolve()方法類似,除了rejecet 代表狀態(tài)為 Rejected,不多說。
Promise.all() 用法
用于將多個Promise 實例包裝成一個新的 Promise實例,參數(shù)為一組 Promise 實例組成的數(shù)組。
var?p??=?Promise.all([p1,p2,p3]);
當 p1, p2, p3 狀態(tài)都 Resolved 的時候,p 的狀態(tài)才會 Resolved;只要有一個實例 Rejected ,此時第一個被 Rejected 的實例的返回值就會傳遞給 P 的回調函數(shù)。
應用場景:假設有一個接口,需要其它兩個接口的數(shù)據(jù)作為參數(shù),此時就要等那兩個接口完成后才能執(zhí)行請求。
var?p1?=?new?Promise((resolve,?reject)?=>?{
????setTimeout(resolve,?1000,?'P1');
});
var?p2?=?new?Promise((resolve,?reject)?=>?{
????setTimeout(resolve,?2000,?'P2');
});
//?同時執(zhí)行p1和p2,并在它們都完成后執(zhí)行then:
Promise.all([p1,?p2]).then((results)?=>?{
????console.log(results);?//?獲得一個Array:?['P1',?'P2']
});
Promise.race() 用法
和Promise.all 類似,區(qū)別是 Promise.race() 只要監(jiān)聽到其中某一個實例改變狀態(tài),它的狀態(tài)就跟著改變,并將那個改變狀態(tài)實例的返回值傳遞給回調函數(shù)。
應用場景: 可以通過多個異步任務來進行容錯處理,多個接口返回同樣的數(shù)據(jù),只要有一個接口生效返回數(shù)據(jù)即可。
Promise.prototype.then()
then 方法是定義在 Promise 的原型對象上的,作用是為 Promise 實例添加狀態(tài)改變時的回調函數(shù);
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);
});
Promise.prototype.catch()
catch 方法是一個語法糖,看下面代碼就明白了,用于指定發(fā)生錯誤時的回調函數(shù)。
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);
})
//?后一種寫法更好,語義更清晰,第一種方法在第一個函數(shù)里面出錯的話時在第二個函數(shù)里監(jiān)聽不到變化的。
Promise.try()
實際開發(fā)中,經(jīng)常遇到一種情況:不知道或者不想?yún)^(qū)分,函數(shù) f 是同步函數(shù)還是異步操作,但是想用 Promise 來處理它。因為這樣就可以不管f是否包含異步操作,都用 then 方法指定下一步流程,用 catch 方法處理 f 拋出的錯誤。
- 第一種方法,缺陷是不能識別同步請求。
const?f?=?()?=>?console.log('now');
Promise.resolve().then(f);
console.log('next');
//?next
//?now
- new Promise() 寫法
const?f?=?()?=>?console.log('now');
(
()?=>?new?Promise(
resolve?=>?resolve(f())
)
)();
console.log('next');
//?now
//?next
- Promise.try 寫法,替代new Promise() 方法,更簡潔。
const?f?=?()?=>?console.log('now');
Promise.try(f);
console.log('next');
//?now
//?next
總結
兩個特點
- 狀態(tài)不受外界影響,只有異步操作的結果會影響到它,pending(進行中),reject(已失敗),resolved(已完成)
- 狀態(tài)只能改變一次
感受:
- promise 首先是一個構造函數(shù),所以需要new 出來一個實例來使用
- 像是一個 ajax 函數(shù)外面加了一層包裹層,封裝了一下下,實現(xiàn)了代碼層面的同步效果
- 很有意思~(廢話)
- 缺點也很明顯,就是代碼語義化不夠,一眼看去都是Promise 的 API,then catch 等等,不能很快明白代碼究竟想表達什么意思,這也是 async 函數(shù)出現(xiàn)的原因,async ,可能是異步操作的終極方案了。
轉載于:https://www.cnblogs.com/zhoumingjie/p/10022355.html
總結
以上是生活随笔為你收集整理的ES6中的Promise详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 万能的涯叔求赐名~?
- 下一篇: 无标题= =