摘要:第一個回調函數完成后,會將返回結果作為參數,傳入第二個回調函數。采用鏈式的,可以指定一組按照次序調用的回調函數。這時,第二個方法指定的回調函數,就會等待這個新的對象狀態發生變化。處理和前一個回調函數運行時發生的錯誤。
1.Promise的含義
Promise是異步編程的一種解決方案,比傳統的解決方案--回調函數和事件更合理更強大。所謂Promise,簡單說就是一個容器,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果。
Promise對象有以下兩個特點:
(1)對象的狀態不受外界影響。Promise對象代表一個異步操作,有三種狀態:pending(進行中)、fulfiled(已成功)和rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,任何其它操作都無法改變這個狀態。
(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從pending變為fulfiled和從pending變為rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱為resolved(已定型)。
缺點:
首先,無法取消Promise,一旦新建他就會立即執行,無法中途取消。其次,如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。第三,當處與pending狀態時,無法得知目前進展到哪一個階段。
下面的代碼創造了一個Promise實例。
const promise = new Promise(function(resolve,reject){ if(/*異步操作成功*/){ resolve(value); }else{ reject(error); } });
Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由JavaScript引擎提供,不用自己部署。
resolve函數的作用是,將Promise對象的狀態從未完成變為成功,在異步操作時調用,并將異步操作的結果,作為參數傳遞出去;reject函數的作用是,將Promise對象的狀態從未完成變為失敗,在異步操作失敗時調用,并將異步操作報出的錯誤,作為參數傳遞出去。
Promise實例生成以后,可以用then方法分別指定resolved狀態和rejected狀態的回調函數。
promise.then(function(value){ //success },function(error){ //failure })
then方法可以接受兩個回調函數作為參數。第一個回調函數是Promsie對象的狀態變為resolved時調用,第二個回調函數是Promise對象的狀態變為rejected時調用。其中,第二個函數是可選的,不一定要提供。這兩個函數都接受Promise對象傳出的值作為參數。
下面是一個Promise對象的簡單例子:
function timeout(ms){ return new Promise((resolve,reject)=>{ setTimeout(resolve,ms,"done"); }) } timeout(100).then((value)=>{ console.log(value); })
上面代碼中,timeout方法返回一個Promise實例,表示一段時間后才會發生的結果。過了指定時間以后,promise實力的狀態變為resolved,就會觸發then方法綁定的回調函數。
Promise新建后就會立即執行。下面代碼中,Promise新建后立即執行,所以首先輸出的是Promise。然后,then方法指定的回調函數,將在當前腳本所有同步任務執行完才會執行,所以resolved最后輸出。
let promise = new Promise(function(resolve,reject){ console.log("Promise"); resolve(1) }); promise.then(function(value){ console.log("resolved"); console.log(value) }); console.log("Hi"); //Promise //Hi! //resolved //1
如果調用resolve函數和reject函數時帶有參數,那么它們的參數會被傳遞給回調函數。reject函數的參數通常是Error對象的實例,表示拋出錯誤;resolve函數的參數除了正常的值以外,還可能是另一個Promise實例。比如像下面這樣。p1和p2都是Promise實例,但是p2的resolve方法將p1作為參數,即一個異步操作的結果返回另一個異步操作。
const p1 = new Promise(function(resolve,reject){ //... }); const p2 = new Promise(function(resolve,reject){ //.... resolve(p1); })
注意:這時p1的狀態就會傳遞給p2,也就是說,p1的狀態決定了p2的狀態。如果p1的狀態是pending,那么p2的回調函數就會等待p1的狀態改變;如果p1的狀態已經是resolved或則rejected,那么p2的回調函數將會立刻執行。
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
上面代碼中,p1是一個Promise,3秒之后變為rejected。p2的狀態在1秒之后改變,resolve方法返回的是p1.由于p2返回的是另一個Promise,導致p2自己的狀態無效了,由p1的狀態決定p2的狀態。所以,后面的then語句都變成針對后者p1.又過了2秒,p1變為rejected,導致觸發catch方法指定的回調函數。
注意:調用resolve或reject并不會終結Promise的參數函數的執行。
new Promise((resolve,reject)=>{ resolve(1); console.log(2); }).then(r=>{ console.log(r); });
上面代碼中,調用resolve(1)以后,后面的console.log(2)還是會執行,并且會首先打印出來。這是因為立即resolved的Promise是在本輪事件循環的末尾執行,總是晚于本輪循環的同步任務。
一般來說,調用resolve或reject以后,Promise的使命就完成了,后繼操作應該放到then方法里面,而不應該直接寫在resolve或reject的后面。所以,最好在它們前面加上return語句,這樣就不會有意外。
new Promise((resolve,reject)=>{ return resolve(1); //后面的語句不會執行 console.log(2); })
demo小例子:
let info =[]; function dog(){ return new Promise(function(resolve,reject){ resolve("一只狗"); }) }; function cat(){ return new Promise(function(resolve,reject){ resolve("一只貓"); }) }; function animal(num){ return new Promise(function(resolve,reject){ info.push(num); console.log(info); resolve(); }) }; dog().then(animal).then(cat).then(animal); //["一只狗"] //["一只狗","一只貓"]Promise.prototype.then()
Promise實例具有then方法,也就是說,then方法是定義在原型對象Promise.prototype上的。它的作用是為Promsie實例添加狀態改變時的回調函數。前面說過,then方法的第一個參數是resolved狀態的回調函數,第二個參數是rejected狀態的回調函數。
then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。因此可以采用鏈式寫法,即then方法后面再調用另一個then方法。
getJson("./index.json").then(function(json){ return json.post; }).then(function(post){ //... });
上面代碼使用then方法,依次指定了兩個回調函數。第一個回調函數完成后,會將返回結果作為參數,傳入第二個回調函數。
采用鏈式的then,可以指定一組按照次序調用的回調函數。這時,前一個回調函數,有可能返回的還是一個Promise對象,這時后一個回調函數,就會等待該Promise對象的狀態發生變化,才會被調用。
getJson("/index.jspn").then(function(post){ return getJson(post.commentURL); }).then(function funcA(comments){ console.log("resolved",comments); },function funcB(err){ console.log("rejected",err) })
上面代碼中,第一個then方法指定的回調函數,返回的是另一個Promise對像。這時,第二個then方法指定的回調函數,就會等待這個新的Promise對象狀態發生變化。如果變為resolved,就調用funcA,如果狀態變為rejected,就調用funcB.
Promise.prototype.catch()Promise.prototype.catch方法是.then(null,rejection)的別名,用于指定發生錯誤時的回調函數。
getJSON("/posts.json").then(function(posts){ //.... }).catch(function(error){ //處理getJSON和前一個回調函數運行時發生的錯誤。 console.log("發生錯誤!",error) });
上面代碼中,getJSON方法返回一個Promise對象,如果該對象狀態變為resolved,則會調用then方法指定的回調函數;如果異步操作拋出錯誤,狀態就會變為rejected,就會調用catch方法指定的回調函數,處理這個錯誤。另外then方法指定的回調函數,如果運行中拋出錯誤,也會被catch方法捕獲。
p.then((val)=>console.log("fulid",val)) .catch((err)=>console.log("reject",err));Promise.prototype.finally()
finally方法用于指定不管Promise對象最后狀態如何,都會執行操作。該方法是ES2018引入標準的。
promise.then(result=>{...}) .catch(error=>{...}) .finally(()=>{...})
上面代碼中,不管promise最后的狀態,在執行完then或catch指定的回調函數以后,都會執行finally方法指定的回調函數。
下面是一個例子,服務器使用Promise處理請求,然后使用finally方法關掉服務器。
server.listen(port).then(function(){ //... }).finally(server.stop);
finally方法的回調函數不接受任何參數,這意味著沒有辦法知道,前面的Promise狀態到底是fulfilled還是rejected。這表明,finally方法里面的操作,應該是與狀態無關的,不依賴于Promise的執行結果。
finally本質上是then方法的特例。
Promise.all方法用于將多個Promise實例,包裝成一個新的promise實例。
const p = Promise.all([p1,p2,p3]);
上面代碼中,Promise.all方法接受一個數組作為參數,p1,p2,p3都是Promise實例,如果不是,就會先調用下面講到的Promise.resolve方法,將參數轉為Promise實例,再進一步處理。
p的我狀態由p1,p2,p3決定,分成兩種情況。
(1)只有p1,p2,p3的狀態都變成fulfilled,p的狀態才會變成fulfilled,此時p1,p2,p3的返回值組成一個數組,傳遞給p的回調函數。
(2)只要p1,p2,p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。
demo
const a = contentData(); const b = a.then(findAll); const c = a.then(getCurrent); Promise.all([ b, c ]).then(([books, user]) => pickTopRecommentations(books, user))
上面代碼中,b和c是兩個異步操作,只有等到它們的結果都返回了,才會觸發pickTopRecommentations這個回調函數。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/99463.html
摘要:下一篇大概就是源碼方面的學習筆記了龜速學習中這一次我是去看了下規范照例傳送門圖靈社區規范首先吧個人總結下該用的詞解決結婚拒絕婉拒終值值傳家寶拒因好人卡等等異常車禍理下概念我們的的就像是一場姻緣對吧解決呢就是結婚成功啦傳家寶也如愿的傳給下一代 下一篇大概就是源碼方面的學習筆記了...龜速學習中... 這一次我是去看了下Promises/A+規范照例傳送門:圖靈社區Promises/A+規...
摘要:版本以及之前,本身還沒有異步執行代碼的能力,宿主環境傳遞給引擎,然后按順序執行,由宿主發起任務。采納引擎術語,把宿主發起的任務稱為宏觀任務,把引擎發起的任務稱為微觀任務。基本用法示例的回調是一個異步的執行過程。 筆記說明 重學前端是程劭非(winter)【前手機淘寶前端負責人】在極客時間開的一個專欄,每天10分鐘,重構你的前端知識體系,筆者主要整理學習過程的一些要點筆記以及感悟,完整的...
摘要:版本以及之前,本身還沒有異步執行代碼的能力,宿主環境傳遞給引擎,然后按順序執行,由宿主發起任務。采納引擎術語,把宿主發起的任務稱為宏觀任務,把引擎發起的任務稱為微觀任務。基本用法示例的回調是一個異步的執行過程。 筆記說明 重學前端是程劭非(winter)【前手機淘寶前端負責人】在極客時間開的一個專欄,每天10分鐘,重構你的前端知識體系,筆者主要整理學習過程的一些要點筆記以及感悟,完整的...
摘要:版本以及之前,本身還沒有異步執行代碼的能力,宿主環境傳遞給引擎,然后按順序執行,由宿主發起任務。采納引擎術語,把宿主發起的任務稱為宏觀任務,把引擎發起的任務稱為微觀任務。基本用法示例的回調是一個異步的執行過程。 筆記說明 重學前端是程劭非(winter)【前手機淘寶前端負責人】在極客時間開的一個專欄,每天10分鐘,重構你的前端知識體系,筆者主要整理學習過程的一些要點筆記以及感悟,完整的...
摘要:異步操作未完成異步操作成功異步操作失敗基本用法是一個構造函數,接收一個參數,這個參數是函數,同時這個參數函數要傳入兩個參數,,分別表示異步操作執行成功后的回調函數和異步操作執行失敗后的回調函數。如果調用函數,就會調用方法的第一個參數。 Promise對象 Promise 表示一個異步操作的最終結果,與之進行交互的方式主要是 then 方法,該方法注冊了兩個回調函數,用于接收 promi...
閱讀 928·2021-11-24 09:38
閱讀 944·2021-11-23 09:51
閱讀 2951·2021-11-16 11:44
閱讀 1782·2021-09-22 15:52
閱讀 1686·2021-09-10 11:20
閱讀 1411·2019-08-30 13:47
閱讀 1305·2019-08-29 12:36
閱讀 3340·2019-08-26 10:43