Promise 承諾
一:promise概念
在js中,promise是一個物件,是專門用來處理非同步操作 / 回撥地獄的,那麼什麼是回撥地獄?涉及到同步和非同步任務的知識,在js中,因為js是單執行緒,無法多併發處理任務,當在js中執行程式碼時,首先會優先執行同步程式碼,而非同步程式碼則必須等到同步程式碼全部執行完才會被執行,那麼每個非同步程式碼的載入都需要時間,有快有慢,當我們需求讓非同步按照我們自己的開發想法來執行,顯然需要進行巢狀才能讓非同步任務有序的按照我們自己的想法執行,就是在這一不斷巢狀的過程中,就會形成回撥地獄,一不便於管理,程式碼耦合嚴重,二程式碼非常難看,那麼promise的出現就解決了這回撥地獄的帶來的不好的體驗。
二:promise的特點
1:在promise中,總共有三種狀態,分別是準備中(pending),成功時(resolved)和失敗時(rejected)
2:一但建立,狀態立即時pending,只有非同步返回的結構可以改變其狀態,且只能由pending—>resolved 或者 pending -->rejected,沒有其他情況
三:promise的語法和方法
(1):使用promise時,需要使用 new 出來
1 var pms = new Promise(function(resolve,reject){ 2 var i = 3; 3 if(i>3){ 4 // resolve 表示正確完成時執行的函式 5 resolve(); 6 }else{ 7 // reject 表示失敗時執行的函式 8 reject(); 9 } 10 }) 11 // 呼叫 promise 下的兩個回撥函式 - then 方法 12 pms.then(function(){ 13 // 當正確時執行 14 console.log('執行resolve回撥函式'); 15 },function(){ 16 // 當失敗時執行 17 console.log('執行reject回撥函式'); 18 })
Promise物件的回撥函式下有兩個引數,都是回撥函式:第一個引數resolved,第二個引數rejected,分別對應成功狀態和失敗狀態,使用then方法來獲取返回的結果和狀態。
Promise的then 方法:promise物件中用來執行回撥函式的方法,then方法接受兩個引數,第一個是成功的resolved的回撥,另一個是失敗rejected的回撥,且第二個失敗的回撥引數可選。並且then方法裡也可以返回promise物件。
(2):promise的狀態只被執行一次
1 // promise 狀態只能被執行一次 2 var pms = new Promise(function(resolve,reject){ 3 // 1:在 promise 中 resolve和reject,只能被呼叫一次,不能同時呼叫 4 // 2:當執行resolve或者reject時,這個Promise當中狀態就會被修改 5 resolve(4) // 只執行第一個,後面的不執行 6 reject(3) 7 resolve(2) 8 reject(1) 9 }) 10 // 呼叫 promise - then方法 11 // catch 方法:是promise中執行 promise發生錯誤時的方法 12 pms.then(function(num){ 13 console.log(num) // 4 14 }).catch(function(num){ 15 console.log(num) 16 })
使用promise,他的狀態要麼從pending改變成resolve,要麼就是從pending改變成reject,當在promise中呼叫多次promise物件的回撥,只會執行一次。
catch 方法:是promise中執行 promise發生錯誤時的方法
(3):promise的resolve和reject方法
1 // Promise.resolve() 方法:直接執行Promise的resolve方法,並且傳入引數 2 // 返回一個Promise物件,狀態為resolve 3 // pmsRes 的狀態為 resolve 4 var pmsRes = Promise.resolve(3).then(function(num){ 5 console.log(num); // 3 6 }) 7 8 // Promise.reject() 方法:直接執行Promise的reject方法,並且傳入引數 9 // 返回一個Promise物件,狀態為rejected 10 // pmsRes 的狀態為 reject 11 var pmsRej = Promise.reject(1).then(function(num){ 12 console.log(num); // Uncaught (in promise) 1 13 })
(4):promise.all()的方法 - all中的引數是一個陣列,陣列中放置的時promise物件,只有當陣列中所有的都執行成resolve狀態,才會執行all方法,注意,一定是所有,有一個是為失敗,all方法不會執行,相當於運算子且 &&
1 function loadImage(src){ 2 var pms = new Promise(function(resolve,reject){ 3 var img = new Image() 4 // 給 img 新增 load事件 和 error事件,由promies 回撥函式返回結果 5 img.onload = function(){ 6 resolve(img); 7 } 8 img.onerror = function(){ 9 // 當錯誤時,執行reject 10 reject(src); 11 } 12 // 給img 新增地址 - 在這裡為同步程式碼 13 img.src = src; 14 }) 15 // 返回這個 promies 物件 16 return pms; 17 } 18 var arr = []; 19 for(var i = 0;i < 5;i++){ 20 var res = loadImage('./images/'+i+'.jpg'); 21 arr.push(res); 22 } 23 // 當arr陣列中所有的都完成了,才會執行all方法 24 Promise.all(arr).then(function(list){ 25 list.forEach(itme=> { 26 // 在這裡只有圖片都完成,才會列印所有圖片的寬度 27 console.log(itme.width); 28 }); 29 })
圖片格式:
(5): 連綴式寫法,處理回撥地獄
1 function loadImage(src){ 2 3 var pms = new Promise(function(resolve,reject){ 4 // 建立圖片 5 var img = new Image() 6 // 給 img 新增 load事件 和 error事件,由promies 回撥函式返回結果 7 img.onload = function(){ 8 // 當正確時,執行resolve 9 resolve(img); 10 } 11 img.onerror = function(){ 12 // 當錯誤時,執行reject 13 reject(src); 14 } 15 // 給img 新增地址 - 在這裡為同步程式碼 16 img.src = src; 17 }) 18 // 返回這個 promies 物件 19 return pms; 20 } 21 // promies 連綴式寫法:結合loadImage函式 22 // then呼叫 return 返回下一次的結果 23 loadImage('./img/5-.jpg').then(function(img){ 24 console.log(img.width,img.src) 25 return loadImage('./img/6-.jpg'); 26 }).then(function(img){ 27 console.log(img.width,img.src) 28 return loadImage('./img/7-.jpg'); 29 }).then(function(img){ 30 console.log(img.width,img.src) 31 return loadImage('./img/8-.jpg'); 32 }).then(function(img){ 33 console.log(img.width,img.src) 34 return loadImage('./img/9-.jpg'); 35 }).then(function(img){ 36 console.log(img.width,img.src); 37 })
如上,通過不斷 return 返回promise物件,那麼圖片的載入就會按照我們自己的想法順序載入。且比較美觀,當圖片較多,可以通過迴圈的方式來返回promise物件,就不需要一直連綴下去了。