JavaScript Promise查缺補漏
Promise簡介
ECMAscript6原生提供了Promise物件,由瀏覽器直接支援,目前大多數瀏覽器都已經實現了,低版本瀏覽器可以使用es6-promise庫來填平相容性問題。Promise最大的好處是把執行程式碼和處理程式碼分離開,使非同步操作邏輯更加清晰。
Promise特點
1、物件的狀態不受外界影響
Promise物件代表一個非同步操作,有三種狀態:
pending - 初始狀態。
fulfilled - 操作成功完成。
rejected - 操作失敗。
只有非同步操作的結果可以決定當前是哪一種狀態,其他操作都不會影響狀態改變,這也是Promise最本質的特性,對於呼叫者的一種承諾
2、一旦狀態改變,就不會再變
Promise物件的狀態改變,只有兩種情況:從Pending變為Resolved和從Pending變為Rejected。只要這兩種情況發生,狀態就會固定,不會再變了,會一直保持這個結果,與事件不同的是,就算改變已經發生了,再對Promise物件新增回撥函式,也會立即得到這個結果,而事件一旦錯過再去監聽,就不會得到結果。
Promise優缺點
優點:
有了Promise物件,就可以將非同步操作以同步操作的流程表達出來,避免了層層巢狀的回撥函式Promise
物件提供統一的介面,使得控制非同步操作更加容易
缺點:
無法取消 Promise,一旦新建它就會立即執行,無法中途取消
如果不設定回撥函式,Promise內部丟擲的錯誤,不會反應到外部
當處於Pending狀態時,無法得知目前進展到哪一個階段(剛剛開始或者即將完成)
Promise.prototype.then
Promise.prototype.then方法返回的是一個新的Promise物件,因此可以採用鏈式寫法
ajax("").then((json) => { return json.post; }).then((post) => { // post處理});
程式碼中使用then方法,指定了兩個回撥函式。第一個回撥函式完成後,會將返回結果作為引數,傳入第二個then中的回撥函式執行。
ajax("").then((jsonURL) => { return ajax(jsonURL); }).then((post) => { // post處理});
如果第一個回撥函式返回的是Promise物件,後一個回撥函式會等待該Promise物件的執行結果,等Promise執行結果返回,再進一步呼叫。
這種設計使得巢狀的非同步操作,可以被很容易得改寫,把回撥函式的"橫向發展"改為了"向下發展"。
Promise.prototype.catch
Promise.prototype.catch錯誤捕捉方法是Promise.prototype.then(null, rejection)的別名,用來指定發生錯誤時的處理函式。
ajax("").then((post) => { throw Error(); }).catch((error) => { // 捕捉回撥函式執行時發生的錯誤進行處理 console.log('error:' + error); });
Promise物件的錯誤具有"冒泡"性質,會一直向後傳遞,直到被捕獲為止。
ajax("").then((jsonURL) => { return ajax(jsonURL); }).then((comments) => { throw Error(); }).catch((error) => { // 處理前兩個回撥函式的錯誤 console.log('error:' + error); });
Promise.resolve
Promise.resolve方法可以將現有物件轉為Promise物件。如果Promise.resolve方法的引數,不是thenable 物件(具有then方法的物件 ),則返回一個新的Promise物件,且它的狀態為fulfilled。
const resolve = Promise.resolve('promise resolve'); resolve.then((s)=>{ console.log(s) }); 輸出結果: promise resolve
如果Promise物件的例項狀態為fulfilled,回撥函式會立即執行,Promise.resolve方法的引數就是回撥函式的引數。
如果Promise.resolve方法的引數是一個Promise物件的例項,則會返回該Promise例項。
Promise.reject
Promise.reject(reason)方法與resolve方法類似,也會返回一個新的Promise例項,但該例項的狀態為rejected。Promise.reject方法的引數,會被傳遞給例項的回撥函式。
const reject = Promise.reject('promise reject'); reject.then(null, (err) => { console.log(err) }); 輸出結果: promise reject
Promise.all
Promise.all方法用於將多個Promise例項,包裝成一個新的Promise例項,該方法一般接受一個陣列作為引數,但不一定是陣列,只要具有iterator介面。且返回的每個成員都是Promise例項。
const getRandom = () => +(Math.random()*1000).toFixed(0);const ajax = (taskID) => new Promise(resolve => { let timeout = getRandom(); console.log(`taskID=${taskID} start.`); setTimeout(function() { console.log(`taskID=${taskID} finished in time=${timeout}.`); resolve(taskID) }, timeout); });Promise.all([ajax(1),ajax(2),ajax(3)]) .then(resultList => { console.log('results:',resultList); }); 輸出結果: taskID=1 start. taskID=2 start. taskID=3 start. taskID=2 finished in time=27.taskID=3 finished in time=257.taskID=1 finished in time=876.results: [1, 2, 3]
Promise.all狀態分為兩種:
只有ajax(1)、ajax(2)、ajax(3)的狀態都變成fulfilled,返回的狀態才會變成fulfilled,此時ajax(1)、ajax(2)、ajax(3)的返回值組成一個陣列,傳遞給Promise.all的回撥函式。
只要ajax(1)、ajax(2)、ajax(3)之中有一個是rejected,返回的狀態就變成rejected,此時第一個被reject的例項的返回值,會傳遞給Promise.all的回撥函式。
Promise.race
Promise.race方法也是將多個Promise例項,包裝成一個新的Promise例項,與Promise.all不同的是一旦有狀態改變,就會返回第一個狀態改變的Promise例項返回值。
const getRandom = () => +(Math.random()*1000).toFixed(0);const ajax = (taskID) => new Promise(resolve => { let timeout = getRandom(); console.log(`taskID=${taskID} start.`); setTimeout(function() { console.log(`taskID=${taskID} finished in time=${timeout}.`); resolve(taskID) }, timeout); });Promise.race([ajax(1),ajax(2),ajax(3)]) .then(result => { console.log('results:',result); }); 輸出結果: taskID=1 start. taskID=2 start. taskID=3 start. taskID=2 finished in time=59.results: 2taskID=3 finished in time=707.taskID=1 finished in time=854.
Promise.race雖然返回第一個狀態改變的Promise例項,但不能阻止其他Promise例項狀態改變。
如果Promise.all方法和Promise.race方法的引數,不是Promise例項,就會呼叫Promise.resolve方法,將引數轉為Promise例項,再進一步處理。
作者:bestvist
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3486/viewspace-2814149/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Typescript 查缺補漏TypeScript
- Flutter查漏補缺1Flutter
- iOS 查漏補缺 - PerformSelectoriOSperformSelector
- ROS灰灰的日常查漏補缺ROS
- C++灰灰的日常查漏補缺C++
- shell基礎知識查缺補漏
- C# 執行緒查漏補缺C#執行緒
- asp.net core 2.0 查缺補漏ASP.NET
- 前端面試查漏補缺--(十三) 記憶體洩漏前端面試記憶體
- 前端面試查漏補缺--(十五) Event Loop前端面試OOP
- 前端面試查漏補缺--(八) 前端加密前端面試加密
- SLAM 灰灰restudy及查漏補缺—octomapSLAMREST
- 技術棧查漏補缺——架構師架構
- 【查漏補缺】那些漏掉的面試知識面試
- C# 執行緒同步查漏補缺C#執行緒
- 查漏補缺(C++筆試)(更新中)C++筆試
- 前端面試查漏補缺--(十) 前端鑑權前端面試
- [學習筆記]TypeScript查缺補漏(一):類筆記TypeScript
- Redis基礎你掌握多少了?來查漏補缺?Redis
- 前端面試查漏補缺--(九) HTTP與HTTPS前端面試HTTP
- 前端面試查漏補缺--(四) 前端本地儲存前端面試
- 前端面試查漏補缺--(二) 垃圾回收機制前端面試
- 圖片載入利器之Picasso(五)查漏補缺
- 「查缺補漏」高頻考點瀏覽器面試題瀏覽器面試題
- 「查缺補漏」鞏固你的Redis知識體系Redis
- 前端面試查漏補缺--(十四) 演算法及排序前端面試演算法排序
- 前端面試查漏補缺--(六) 瀏覽器快取前端面試瀏覽器快取
- 前端面試查漏補缺--(一) 防抖和節流前端面試
- [查漏補缺]正規表示式匹配演算法演算法
- Go語言學習查缺補漏ing Day8Go
- Go語言學習查缺補漏ing Day6Go
- Go語言學習查缺補漏ing Day7Go
- Go語言學習查缺補漏ing Day3Go
- Go語言學習查缺補漏ing Day4Go
- Go語言學習查缺補漏ing Day5Go
- Go語言學習查缺補漏ing Day1Go
- Go語言學習查缺補漏ing Day2Go
- [筆記](更新中)CSP-S 2024 查漏補缺筆記