大白話透徹講解 Promise 的使用,讀完你就懂了


一、為什么使用Promise?

我們知道 js 執行的時候,一次只能執行一個任務,它會阻塞其他任務。由於這個缺陷導致 js 的所有網絡操作,瀏覽器事件,都必須是異步執行。異步執行可以使用回調函數執行。

常見的異步模式有以下幾種:

  • 定時器
  • 接口調用
  • 事件函數
// setTimeout 示例
function callBack(){
 console.log('執行完成')
}
console.log('before setTimeout')
setTimeout(callBack,1000)// 1秒后調用callBack函數
console.log('after setTimeout')

運行后控制台輸出結果為:

before setTimeout after setTimeout 執行完成 //1秒后打印

上述定時器是在固定時間觸發某個回調函數。

對於 ajax 網絡請求就沒有這么簡單了,可能有多個網絡請求是關聯的,先執行某個請求返回結果后,第一個返回結果作為第二個請求的參數,調用第二個網絡請求。如此,如果業務復雜,網絡請求太多時,回調也很多,容易出現回調地獄。所以 Promise 出現了,專門解決異步回調地獄問題。

Promise 翻譯成中文:承諾、保證。

通俗地講,Promise 就像一個容器,里面存放着未來才會結束,返回結果的容器,返回的結果只需要在出口處接收就好了。從語法上講,Promise 是一個對象,從它可以獲取異步操作的消息。

二、Promise基本使用

下列用到的所有定時器模擬我們的 ajax 請求。

Promise 實例化的時候,傳入的參數是一個函數,函數中接收兩個參數:

const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
 resolve('123')
 },1000)
}).then(res=>{
 console.log(res) //1秒后打印123
})

傳入的 resolve 和 reject 本身都是函數。其作用分別為:

resolve - 把 Promise 的狀態從進行中變為成功狀態。

reject - 把 Promise 的狀態從進行中變為拒絕狀態。

Promise的三種狀態:

pending :進行中,表示 Promise 還在執行階段,沒有執行完成。

fulfilled:成功狀態,表示 Promise 成功執行完成。

rejected:拒絕狀態,表示 Promise 執行被拒絕,也就是失敗。

Promise 的狀態,只可能是其中一種狀態,從進行中變為成功或失敗狀態之后,狀態就固定了,不會再發生改變。

Promise.then

執行 resolve 時,Promise 狀態變為 fulfilled ,會執行 .then 方法。then 方法接收的參數也是一個函數,函數中攜帶一個參數,該參數是 resolve(res) 返回的數據。

const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
 resolve('哎呦喂')
 },1000)
}).then(res=>{
 console.log(res) //1秒后打印哎呦喂
})

Promise.catch

執行 reject 時,Promise 狀態從 pending 變為 rejected,會執行 catch 方法,catch 方法接收的也是一個函數,函數中攜帶一個參數,該參數為 reject(err) 返回的數據。

const p = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  reject('error message')
  },1000)
 }).then(res=>{
  console.log(res)//不執行
 }).catch(err=>{
  console.log('err',err)//1秒后打印 error message
})

三、Promise 鏈式調用

制作一個模擬網絡請求:

  • 第一次返回 a,
  • 修改返回的結果為 aa,作為第二次網絡請求返回的結果。
  • 修改結果為 aaa,作為第三次返回結果。
const pp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  resolve('a')
 },1000)
}).then(res=>{
 console.log('res1',res) //1秒后打印 a
 return new Promise((resolve,reject)=>{
  setTimeout(()=>{
   resolve(res+'a')
   },1000)
 })
}).then(res=>{
  console.log('res',res) //2秒后打印 aa
  return new Promise((resolve,reject)=>{
   setTimeout(()=>{
    resolve(res+'a')
    },1000)
  })
 }).then(res=>{
  console.log('res3',res) //3秒后打印 aaa
})

這種場景其實就是接口的多層嵌套使用,Promise 可以把多層嵌套按照線性的方式進行書寫,非常優雅。我們把 Promise 的多層嵌套調用就叫做鏈式調用。

上述實例,有三層嵌套就 new 了 3 個Promise,代碼寫得比較多,我們看看在實現功能的前提下如何能夠簡化。

四、Promise 嵌套使用的簡寫

promise傳入的函數參數reject是一個非必傳的參數,如果不需要處理失敗時的結果時,我們可以省略掉 reject 。代碼如下:

//簡化1
const ppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  resolve('a')
  },1000)
 }).then(res=>{
  console.log('res1',res)
  return new Promise(resolve=>resolve(res+'a'))
}).then(res=>{
 console.log('res',res)
 return new Promise(resolve=>resolve(res+'a'))
}).then(res=>{
 console.log('res3',res)
})

Promise 嵌套使用時,內層的 Promise 可以省略不寫,所以我們可以直接把 Promise 相關的去掉,直接返回,代碼如下:

//簡化2
const pppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  resolve('a')
 },1000)
}).then(res=>{
 return  res+'a'
}).then(res=>{
 return res+'a'
}).then(res=>{
 console.log('res3',res)
})

有的同學就在想,怎么都是成功狀態的舉例和簡寫,我們的失敗狀態catch可以簡寫嗎?

答案是肯定的,我們簡化為2層嵌套,與上述功能一致。

const ppppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  reject('a')
 },1000)
}).catch(err=>{
 return new Promise((resolve,reject)=>{
  setTimeout(()=>{
   reject(err+'a')
  },1000)
 })
}).catch(err=>{
 console.log('err',err)
})
 //簡寫1
const pppppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  reject('a')
  },1000)
 }).catch(err=>{
  return new Promise((resolve,reject)=>reject(err+'a'))
 }).catch(err=>{
  console.log('err',err)
 })
 //簡寫2
const ppppppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  reject('a')
  },1000)
 }).catch(err=>{
  throw err+'a'
 }).catch(err=>{
  console.log('err',err)
})

注意:失敗簡寫省略掉Promise時,使用的 throw 拋出異常。

五、Promise方法

5.1、all 方法

Promise.all 方法,提供了並行執行異步操作的能力,並且在所有異步操作完成之后,統一返回所有結果。具體使用如:

Promise.all([
 new Promise(resolve=>resolve('a')),
 new Promise(resolve=>resolve('b')),
]).then(res=>{
 console.log('all',res)//【'a' , 'b'】
 })

all 接收到的是一個數組,數組長度取決於 Promise 的個數。

一些游戲類的素材比較多的應用,打開網頁時,預先加載需要用到的各類資源,所有的都加載完后,再進行頁面的初始化。

5.2、race方法

race翻譯成中文:賽跑。就是誰跑得最快,誰才能觸碰到終點的勝利線。

Promise.race 用法與 all 一樣,只是返回結果上不同,它返回的是執行最快的那個 Promise 的結果。

Promise.race([
 new Promise(resolve=>
  setTimeout(()=>{
   resolve('a')
   },100)
  ),
 new Promise(resolve=>
  setTimeout(()=>{
   resolve('a')
   },200)
  ),
 ]).then(res=>{
  console.log('race',res) // 返回 a
})

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM