Promise對象的基礎(chǔ)入門學(xué)習(xí)
今天來學(xué)習(xí)下Promise吧!其實(shí)這在筆試上也是一個考點(diǎn)。
基本介紹
Promise對象是CommonJS(熟悉的名字吧- -)工作組提出的規(guī)范.Promise原本只是社區(qū)提出的構(gòu)想,一些外部函數(shù)庫率先實(shí)現(xiàn)了該功能,ES6中將其寫入了語言標(biāo)準(zhǔn).
目的:為異步操作提供統(tǒng)一接口
Promise是啥,它就是一個javascript中一個對象,起著代理作用,充當(dāng)異步操作與回調(diào)函數(shù)之間的中介。
避免類似于
這種嵌套地獄的產(chǎn)生.讓我們的代碼變得更加簡單易讀使用了Promise,大家都說好
- (new Promise(f1).then(f2));
總結(jié):Promise使得異步操作的向下發(fā)展變成橫向發(fā)展,程序流程變得清晰,易于閱讀。
基本思想
- 異步任務(wù)返回一個Promise對象,它有三種狀態(tài)
1.pending(未完成)
2.resolved,fulfilled(已完成)
3.rejected(失敗)
- 它有兩種變化途徑
1.pending --> resolved/fulfilled
2.pending --> rejected
- 它有兩種結(jié)果
1.異步操作成功,返回一個值,狀態(tài)變?yōu)閞esolved
2.異步操作失敗,拋出一個錯誤,狀態(tài)變?yōu)閞ejected
Promise使用.then()方法添加回調(diào)函數(shù),then接收兩個回調(diào)函數(shù),***個為成功時的回調(diào)函數(shù),另一個為失敗時的回調(diào)函數(shù).主要為狀態(tài)改變時調(diào)用相對的回調(diào)函數(shù).
而且then可以鏈?zhǔn)秸{(diào)用。
基本使用
Promise構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù),而該函數(shù)兩個參數(shù)分別是resolve和reject.它們由JS引擎提供,不需要自己部署.
- Promise(function(resolve,reject){})
resolve函數(shù)作用為:將Promise對象從未完成變?yōu)槌晒?Pending->Resolved),異步操作成功時調(diào)用,并將異步操作的結(jié)果作為參數(shù)傳遞出去.
reject函數(shù)作用為:將Promise對象從未完成變?yōu)槭?Pending->Rejected),異步操作失敗時調(diào)用,并將異步操作報出的錯誤作為參數(shù)傳遞出去.
Promise.then()方法可以用于指定Resolved狀態(tài)和Reject狀態(tài)的回調(diào)函數(shù).
- promise.then(function(value){//成功+_+!},function(value){//失敗Q_Q});
我們只想對異常進(jìn)行處理時可以采用promise.then(undefined, onRejected)這種方式,或者promise.catch(onRejected)
!注意!此處有坑,接下來在深入節(jié)會進(jìn)行講解
Promise.all()方法接收一個promise對象的數(shù)組為參數(shù),當(dāng)這個數(shù)組中所有的Promise對象全部變成resolve/reject狀態(tài)的時候,才會調(diào)用.then方法,其中傳入的promise是同時開始,并行執(zhí)行的。
- promise.all([promise1,promise2,.....]);
Promise.race()方法和Promise.all()方法一樣接收一個promise對象的數(shù)組作為參數(shù),但是數(shù)組中有一個promise對象進(jìn)入fulfilled或rejected狀態(tài),就會開始后續(xù)處理.
- promise.race([promise1,promise2,.....]);
相關(guān)的語法糖
- Promise.resolve(42);
- //等價于
- new Promise(function(resolve){
- resolve(42);
- });
- Promise.reject(new Error("出錯了"));
- //等價于
- new Promise(function(resolve,reject){
- reject(new Error("出錯了"));
- });
深入
關(guān)于Thenable對象
這是非常類似于Promise的東西,擁有.then方法.
其中比較經(jīng)典的例子就是jQuery.ajax()返回的值就是thenable的.
- var promise = Promise.resolve($.ajax('/json/comment.json'));
這樣就可以將thenable對象轉(zhuǎn)化為promise對象
傳送門:Promise.resolve()
關(guān)于promise設(shè)計:總是異步操作
看代碼就能明白這個地方的問題了.
- var promise = new Promise(function (resolve){
- console.log("inner promise"); // 1
- resolve(42);
- });
- promise.then(function(value){
- console.log(value); // 3
- });
- console.log("outer promise"); // 2
- //結(jié)果是
- /*
- inner promise // 1
- outer promise // 2
- 42 // 3
- */
可以看出,即使我們調(diào)用promise.then時promise對象已經(jīng)確定狀態(tài),Promise也會以異步的方式調(diào)用回調(diào)函數(shù),這就是Promise設(shè)計上的規(guī)定方針.
關(guān)于調(diào)用then/catch
每次調(diào)用then/catch,都會返回一個promise對象,這一點(diǎn)上我們通過使用===就可以判斷出來每次promise對象其實(shí)都是不一樣的
then和catch的錯誤處理區(qū)別
這點(diǎn)和上一點(diǎn)聯(lián)合起來很容易理解
直接上圖吧,來自于JavaScript Promise迷你書(中文版)
在結(jié)合我們的代碼吧
- // <1> onRejected不會被調(diào)用
- function badMain(onRejected) {
- return Promise.resolve(42).then(throwError, onRejected);
- }
- // <2> 有異常發(fā)生時onRejected會被調(diào)用
- function goodMain(onRejected) {
- return Promise.resolve(42).then(throwError).catch(onRejected);
- }
onFullfilled中發(fā)生的錯誤,如在<1>里面throwError中的錯誤,是不會導(dǎo)致onRejected的執(zhí)行(捕獲異常)的,我們只能通過后面的catch方法才能捕獲.
基本應(yīng)用
不兼容方面
- 不兼容就是用polyfill吧
- 關(guān)于IE8以及以下版本中,catch會由于在ES3中為保留字,導(dǎo)致identifier not found錯誤,對此我們可以通過["catch"]或者then(undefined,function(){})來進(jìn)行catch,而某些類庫中,采用了caught作為函數(shù)名來規(guī)避該問題.值得注意的是,有很多壓縮工具中自帶了.catch轉(zhuǎn)["catch"]
應(yīng)用示例:
加載圖片
- var preloadImage = function(path){
- return new Promise(function(resolve,reject){
- var image = new Image();
- image.onload = resolve;
- image.onerror = reject;
- image.src = path;
- })
- }
- preloadImage("https://dn-anything-about-doc.qbox.me/teacher/QianDuan.png").then(function(){
- alert("圖片加載成功");
- },function(){
- alert("圖片加載失敗");
- })
Ajax操作
- function search(term) {
- var url = 'http://example.com/search?q=' + term;
- var xhr = new XMLHttpRequest();
- var result;
- var p = new Promise(function(resolve, reject) {
- xhr.open('GET', url, true);
- xhr.onload = function(e) {
- if (this.status === 200) {
- result = JSON.parse(this.responseText);
- resolve(result);
- }
- };
- xhr.onerror = function(e) {
- reject(e);
- };
- xhr.send();
- });
- return p;
- }
- search("Hello World").then(console.log, console.error);
回到最初吧,其實(shí)Promise對象優(yōu)點(diǎn)還是在于規(guī)范的鏈?zhǔn)秸{(diào)用,可以清晰看出程序流程.并且對于錯誤還能定義統(tǒng)一的處理方法。