摘要:異常一旦得到處理,返回的后續對象將恢復正常,并會被執行成功的回調函數處理。另外,需要注意多級的回調函數是交替執行的,這正是由回調的異步性決定的。
1.Promise的立即執行性
var p = new Promise(function(resolve, reject){ console.log("create a promise"); resolve("success"); }); console.log("after new Promise"); p.then(function(value){ console.log(value); });
控制臺輸出:
"create a promise" "after new Promise" "success"
Promise對象表示未來某個將要發生的事件,但在創建(new)Promise時,作為Promise參數傳入的函數是會被立即執行的,只是其中執行的代碼可以是異步代碼。有些同學會認為,當Promise對象調用then方法時,Promise接收的函數才會執行,這是錯誤的。因此,代碼中"create a promise"先于"after new Promise"輸出。
2.Promise 三種狀態var p1 = new Promise(function(resolve,reject){ resolve(1); }); var p2 = new Promise(function(resolve,reject){ setTimeout(function(){ resolve(2); }, 500); }); var p3 = new Promise(function(resolve,reject){ setTimeout(function(){ reject(3); }, 500); }); console.log(p1); console.log(p2); console.log(p3); setTimeout(function(){ console.log(p2); }, 1000); setTimeout(function(){ console.log(p3); }, 1000); p1.then(function(value){ console.log(value); }); p2.then(function(value){ console.log(value); }); p3.catch(function(err){ console.log(err); });
控制臺輸出:
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1} Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined} Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined} 1 2 3 Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 2} Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: 3}
Promise的內部實現是一個狀態機。Promise有三種狀態:pending,resolved,rejected。當Promise剛創建完成時,處于pending狀態;當Promise中的函數參數執行了resolve后,Promise由pending狀態變成resolved狀態;如果在Promise的函數參數中執行的不是resolve方法,而是reject方法,那么Promise會由pending狀態變成rejected狀態。
p2、p3剛創建完成時,控制臺輸出的這兩臺Promise都處于pending狀態,但為什么p1是resolved狀態呢? 這是因為p1 的函數參數中執行的是一段同步代碼,Promise剛創建完成,resolve方法就已經被調用了,因而緊跟著的輸出顯示p1是resolved狀態。我們通過兩個setTimeout函數,延遲1s后再次輸出p2、p3的狀態,此時p2、p3已經執行完成,狀態分別變成resolved和rejected。
3.Promise 狀態的不可逆性var p1 = new Promise(function(resolve, reject){ resolve("success1"); resolve("success2"); }); var p2 = new Promise(function(resolve, reject){ resolve("success"); reject("reject"); }); p1.then(function(value){ console.log(value); }); p2.then(function(value){ console.log(value); });
控制臺輸出:
"success1" "success"
Promise狀態的一旦變成resolved或rejected時,Promise的狀態和值就固定下來了,不論你后續再怎么調用resolve或reject方法,都不能改變它的狀態和值。因此,p1中resolve("success2")并不能將p1的值更改為success2,p2中reject("reject")也不能將p2的狀態由resolved改變為rejected.
4.鏈式調用var p = new Promise(function(resolve, reject){ resolve(1); }); p.then(function(value){ //第一個then console.log(value); return value*2; }).then(function(value){ //第二個then console.log(value); }).then(function(value){ //第三個then console.log(value); return Promise.resolve("resolve"); }).then(function(value){ //第四個then console.log(value); return Promise.reject("reject"); }).then(function(value){ //第五個then console.log("resolve: "+ value); }, function(err){ console.log("reject: " + err); })
控制臺輸出:
1 2 undefined "resolve" "reject: reject"
Promise對象的then方法返回一個新的Promise對象,因此可以通過鏈式調用then方法。then方法接收兩個函數作為參數,第一個參數是Promise執行成功時的回調,第二個參數是Promise執行失敗時的回調。兩個函數只會有一個被調用,函數的返回值將被用作創建then返回的Promise對象。這兩個參數的返回值可以是以下三種情況中的一種:
return 一個同步的值 ,或者 undefined(當沒有返回一個有效值時,默認返回undefined),then方法將返回一個resolved狀態的Promise對象,Promise對象的值就是這個返回值。
return 另一個 Promise,then方法將根據這個Promise的狀態和值創建一個新的Promise對象返回。
throw 一個同步異常,then方法將返回一個rejected狀態的Promise, 值是該異常。
根據以上分析,代碼中第一個then會返回一個值為2(1*2),狀態為resolved的Promise對象,于是第二個then輸出的值是2。第二個then中沒有返回值,因此將返回默認的undefined,于是在第三個then中輸出undefined。第三個then和第四個then中分別返回一個狀態是resolved的Promise和一個狀態是rejected的Promise,依次由第四個then中成功的回調函數和第五個then中失敗的回調函數處理。
5.Promise then() 回調異步性var p = new Promise(function(resolve, reject){ resolve("success"); }); p.then(function(value){ console.log(value); }); console.log("which one is called first ?");
控制臺輸出:
"which one is called first ?" "success"
Promise接收的函數參數是同步執行的,但then方法中的回調函數執行則是異步的,因此,"success"會在后面輸出。
6.Promise 中的異常var p1 = new Promise( function(resolve,reject){ foo.bar(); resolve( 1 ); }); p1.then( function(value){ console.log("p1 then value: " + value); }, function(err){ console.log("p1 then err: " + err); } ).then( function(value){ console.log("p1 then then value: "+value); }, function(err){ console.log("p1 then then err: " + err); } ); var p2 = new Promise(function(resolve,reject){ resolve( 2 ); }); p2.then( function(value){ console.log("p2 then value: " + value); foo.bar(); }, function(err){ console.log("p2 then err: " + err); } ).then( function(value){ console.log("p2 then then value: " + value); }, function(err){ console.log("p2 then then err: " + err); return 1; } ).then( function(value){ console.log("p2 then then then value: " + value); }, function(err){ console.log("p2 then then then err: " + err); } );
控制臺輸出:
p1 then err: ReferenceError: foo is not defined p2 then value: 2 p1 then then value: undefined p2 then then err: ReferenceError: foo is not defined p2 then then then value: 1
Promise中的異常由then參數中第二個回調函數(Promise執行失敗的回調)處理,異常信息將作為Promise的值。異常一旦得到處理,then返回的后續Promise對象將恢復正常,并會被Promise執行成功的回調函數處理。另外,需要注意p1、p2 多級then的回調函數是交替執行的 ,這正是由Promise then回調的異步性決定的。
7.Promise.resolve()var p1 = Promise.resolve( 1 ); var p2 = Promise.resolve( p1 ); var p3 = new Promise(function(resolve, reject){ resolve(1); }); var p4 = new Promise(function(resolve, reject){ resolve(p1); }); console.log(p1 === p2); console.log(p1 === p3); console.log(p1 === p4); console.log(p3 === p4); p4.then(function(value){ console.log("p4=" + value); }); p2.then(function(value){ console.log("p2=" + value); }) p1.then(function(value){ console.log("p1=" + value); })
控制臺輸出:
true false false false p2=1 p1=1 p4=1
Promise.resolve(...)可以接收一個值或者是一個Promise對象作為參數。當參數是普通值時,它返回一個resolved狀態的Promise對象,對象的值就是這個參數;當參數是一個Promise對象時,它直接返回這個Promise參數。因此,p1 === p2。但通過new的方式創建的Promise對象都是一個新的對象,因此后面的三個比較結果都是false。另外,為什么p4的then最先調用,但在控制臺上是最后輸出結果的呢?因為p4的resolve中接收的參數是一個Promise對象p1,resolve會對p1”拆箱“,獲取p1的狀態和值,但這個過程是異步的,可參考下一節。
8.resolve vs rejectvar p1 = new Promise(function(resolve, reject){ resolve(Promise.resolve("resolve")); }); var p2 = new Promise(function(resolve, reject){ resolve(Promise.reject("reject")); }); var p3 = new Promise(function(resolve, reject){ reject(Promise.resolve("resolve")); }); p1.then( function fulfilled(value){ console.log("fulfilled: " + value); }, function rejected(err){ console.log("rejected: " + err); } ); p2.then( function fulfilled(value){ console.log("fulfilled: " + value); }, function rejected(err){ console.log("rejected: " + err); } ); p3.then( function fulfilled(value){ console.log("fulfilled: " + value); }, function rejected(err){ console.log("rejected: " + err); } );
控制臺輸出:
p3 rejected: [object Promise] p1 fulfilled: resolve p2 rejected: reject
Promise回調函數中的第一個參數resolve,會對Promise執行"拆箱"動作。即當resolve的參數是一個Promise對象時,resolve會"拆箱"獲取這個Promise對象的狀態和值,但這個過程是異步的。p1"拆箱"后,獲取到Promise對象的狀態是resolved,因此fulfilled回調被執行;p2"拆箱"后,獲取到Promise對象的狀態是rejected,因此rejected回調被執行。但Promise回調函數中的第二個參數reject不具備”拆箱“的能力,reject的參數會直接傳遞給then方法中的rejected回調。因此,即使p3 reject接收了一個resolved狀態的Promise,then方法中被調用的依然是rejected,并且參數就是reject接收到的Promise對象。
歡迎關注我的公眾號:老干部的大前端,領取21本大前端精選書籍!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84308.html
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:忍者級別的函數操作對于什么是匿名函數,這里就不做過多介紹了。我們需要知道的是,對于而言,匿名函數是一個很重要且具有邏輯性的特性。通常,匿名函數的使用情況是創建一個供以后使用的函數。 JS 中的遞歸 遞歸, 遞歸基礎, 斐波那契數列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執行機制 本文的目的就是要保證你徹底弄懂javascript的執行機制,如果...
摘要:前端日報精選庖丁解牛二深入解析模板字符串八段代碼徹底掌握高效壓縮文件束的體積譯才不是什么黑魔法呢發布中文譯數據結構棧與隊列瘋狂的技術宅中自定義指令修仙之路更好的異步解決方案發布同步代碼書寫異步情懷有贊前端團隊位運算,也許 2017-07-26 前端日報 精選 庖丁解牛React-Redux(二): connect深入解析 ES6:模板字符串_ES6八段代碼徹底掌握Promise高效壓縮...
閱讀 1319·2021-11-24 09:38
閱讀 3256·2021-11-22 12:03
閱讀 4158·2021-11-11 10:59
閱讀 2317·2021-09-28 09:36
閱讀 1032·2021-09-09 09:32
閱讀 3412·2021-08-05 10:00
閱讀 2528·2021-07-23 15:30
閱讀 2973·2019-08-30 13:12