參考:阮一峯es6(http://es6.ruanyifeng.com/#docs/promise)javascript
時間:2018-07-03java
類型:我的筆記es6
解決的問題:異步編程的一種解決方案。編程
定義:Promise是一個保存着將來纔會執行的事件的容器,建立後就會執行,但它有resolve和reject,做爲將來會執行的事件,等Promise實例執行纔會調用。json
形式:數組
1 //定義一個Promise實例 2 const promise=new Promise(function(resolve,reject){ 3 console.log('我是Promise內同步的'); 4 setTimeout(function(){ 5 console.log('我是定時器') 6 },1) 7 resolve(); 8 }) 9 //執行promise 10 promise.then(function(){ 11 console.log('我是resolve') 12 }); 13 console.log('我是同步的2')
分析:Promise建立,內部的同步會當即執行,因此輸出:promise
「我是Promise內同步的」 「我是同步的2」異步
而後執行異步:一個定時器和promise實例的resolve,定時器自己就是在同步執行完才執行的,promise.then執行後定時器開始執行;異步編程
接着會輸出:「我是resolve」 「我是定時器」函數
寫到這裏其實和異步沒有任何關係,因此來個異步請求開開眼
1 //Promise幹倒Ajax 2 const getJSON=function(url){ 3 const anyName=new Promise(function(resolve,reject){ 4 const xhr=new XMLHttpRequest(); 5 xhr.open('GET',url); 6 xhr.onreadystatechange=handler; 7 xhr.send(); 8 const handler = function() { 9 if(xhr.readyState!==4){ 10 return; 11 } 12 if (xhr.status ===200) { 13 resolve(xhr.response) 14 }else{ 15 reject(new Error(xhr.statusText)) 16 } 17 } 18 }) 19 return anyName; 20 } 21 getJSON('我是路徑url').then(function(json){ 22 console.log(json+'是Promise實例anyName執行成功resolve傳過來的') 23 },function(error){ 24 console.error('出錯了',error) 25 })
胡亂分析:上述代碼的目的是用Promise封裝一個Ajax,爲撒呢,假若有時候咱們須要某一段代碼的執行是在異步以後返回結果執行,這樣寫就不用把代碼寫在success或者失敗裏,把成功或者失敗分別封裝在resolve或者reject,then裏的函數就是指這兩個。
特色:
1.Promise有三種狀態:pending(在進行)resolve(成功)reject(失敗)
2.狀態一旦改變,就不會在變。除非你修改代碼,刷新從新加載。(我很認真)
簡記:(簡單記憶)
const anyNamePromise = new Promise(function(resolve,reject){ ***我是異步代碼***; //判斷異步返回狀態 if (status ===200 ){ //成功了唄,保存成功以後要執行的函數 resolve('我是要傳的參數') }else{ //失敗了唄,保存失敗要執行的函數 reject('沒啥,哥告訴你咋錯的') } }) //告訴你怎麼調用resolve和reject,否則不是乾瞪眼(不是打牌那個,不要打牌,娛樂也不要) anyNamePromise.then(function('resolve傳過來的'){ //少俠能夠在這裏寫成功後的要執行的 },function('我也是傳過來的'){ //不得不說你猜對了,這裏是失敗後要執行的 }) //騷等,會不會以爲這樣寫不太好看,再來一種寫法,這個比較經常使用 anyNamePromise.then(function(){}).catch(function(error){}) //Promise東西好多啊,繼續寫,emmm
擴展:
1.resolve的參數除了正常點的值外還能夠是另外一個Promise實例:
const p1=new Promise(function(resolve,reject){ setTimeout(()=>{reject(new Error('fail'))},2) }) const p2=new Promise(function(resolve,reject){ setTimeout(()=>{resolve(p1)},2) })
p2.then(function(){}).catch(function(){})
解析:p1的狀態決定p2的狀態;p2會等着p1狀態變爲成功或者失敗再決定本身的狀態;
2.then
then返回的是一個新的promise實例,then後還能夠.then,前一個then return回的值能夠被當前的then做爲參數傳遞使用,前一個then的狀態變化,決定後續執行成功仍是失敗的then
1 getJSON('url') 2 .then(()=>{getJSON('newURl')}) 3 .then(()=>{},()=>{})
3.catch
處理錯誤
p.then(()=>{}) .catch(()=>{}); 等價於 p.then(()=>{},()=>{})
優先使用catch,由於catch也會把then執行的錯誤也捕獲,catch後.catch會把前一個catch的錯誤捕捉;和try catch不一樣,Promise對象拋出的錯誤不會傳遞到外部,即不會有任何反應
1 function getFn(){ 2 return new Promise((resolve,reject)=>{ 3 resolve(x+3) 4 }) 5 } 6 getFn().then(()=>{console.log('haha')}); 7 setTimeOut(()=>{console.log('jh')},4)
解析:Promise內部雖然沒有聲明x會報錯,但並不影響後面定時器的執行,錯誤被Promise吃了
建議:Promise後跟着catch方法,處理Promise內部的錯誤。catch方法返回的仍是個Promise對象,也能夠接着調用then。
4.finally
2018引入的
promise .then(()=>{}) .catch(()=>{}) .finally(()=>{})
finally最後都會被執行,不接受任何參數;
5.all
const p = Promise.all([p1,p2,p3])
解析:p1,p2,p3是Promise實例,p的狀態僅當p1,p2,p3都爲resolve才resolve,此時p1,p2,p3的值會組成數組返回給p;
只要有一個rejected,p就會變成rejected,此時第一個被rejected的值傳回給p
const promises=[2,3,4].map(function(val){ return getJSON('url'+val) }) Promise.all(promises) .then(posts=>{console.log(posts)}) .catch((err)=>{console.log(err)})
若p1,p2,p3有catch,則返回均爲resolve,由於若rejected則會被catch捕獲,返回一個新的promise實例,狀態resolved。
6.race
1 const p=Promise.race([p1,p2,p3]) 2 //例子 3 const p=Promise.race([ 4 fetch('隨意實例'), 5 new Promise((resolve,reject){ 6 setTimeout(()=>{reject(new Error('hello'))},10) 7 }) 8 ]); 9 p 10 .then(console.log('hoi')) 11 .catch(console.error);
競賽執行
9.應用
加載圖片
const preImgLoad=function(url){ const promise = new Promise((resolve,reject)=>{ let img = new Image(); img.src=url; img.onload=resolve; img.onerror=reject; }) }
總結:promise裏包含着一個異步執行的結果,成功或者失敗,成功resolve和失敗reject兩個函數對應異步結果。通常.then後.catch捕獲錯誤,Promise能夠把錯誤吃了。race和all是多個Promise實例執行,race是競賽,誰先執行完返回誰,all是返回最後結果,若都resolve,則返回結果放在數組裏傳給all,catch後返回的是一個新的Promise實例,其狀態由catch自己決定。finally不管怎樣都會執行的。