解析Promise解決非同步回撥

千鋒IT教育發表於2023-03-16

Promise是ES6語法中新增的一個標準內建物件,它代表了一個非同步操作的最終完成或者失敗,能夠把非同步操作最終的成功返回值或者失敗原因和相應的處理函式關聯起來,是非同步“回撥地獄”的解決方案之一。


1 應用場景

要了解Promise物件,首先要了解這個物件的應用場景,Promise物件主要就是為瞭解決非同步回撥地獄問題的,那麼什麼是回撥函式呢?請看下面的一段程式碼:

// 定義一個函式a
function a(cb) {
  cb()
}
// 定義一個函式b
function b() {
  console.log('我是函式 b')
}
// 在函式a呼叫的時候,把函式b位置函式a的實參傳入
a(b)

此時,函式a和函式a的引數都是一個函式,為了便於區別,我們把作為函式a引數傳入的那個函式b叫做函式a的回撥函式,我們為什麼需要回撥函式?

當我們執行一個非同步的行為的時候,我們需要在一個非同步行為執行完畢之後做一些事情,那麼,我們是沒有辦法提前預知這個非同步行為是什麼時候完成的,我們就只能以回撥函式的形式來進行,比如我們需要透過ajax請求一個資料,根據ajax返回的結果執行不同的程式碼,但是我們不知道ajax物件什麼時候能獲取到返回結果,就需要使用回撥函式,看下面的程式碼:

// 定義data變數使用者儲存ajax獲取到的資料 let data = null;
 // 執行ajax獲取資料的函式 function getData(){
   let xhr = new XMLHttpRequest();
   xhr.open('GET','/data.json');
   // 監聽ajax的onload事件,事件觸發的時候就是請求完成的時候   xhr.onload = function(){
     // 請求完成,ajax獲取到的資料賦值給data     data = xhr.responseText;
   }
   xhr.send(null)
 }
 // ajax成功返回資料以後,根據返回的資料執行的程式碼 function showData(){
   document.body.innerHTML = data;
 }
 getData();
 showData();

如果採用上面的呼叫方式,先呼叫getData獲取資料以後直接呼叫showData顯示資料,那麼document.body.innerHTML = null,因為此時data還沒有獲取到資料,請求時非同步的,我們需要在請求完成的時候呼叫showData才行,也就是像下面這樣呼叫

// 定義data變數使用者儲存ajax獲取到的資料  let data = null;
  // 執行ajax獲取資料的函式  function getData(cb){
    let xhr = new XMLHttpRequest();
    xhr.open('GET','/data.json');
    // 監聽ajax的onload事件,事件觸發的時候就是請求完成的時候    xhr.onload = function(){
      // 請求完成,ajax獲取到的資料賦值給data      data = xhr.responseText;
      // 之後再呼叫傳入的showData函式      cb();
    }
    xhr.send(null)
  }
  // ajax成功返回資料以後,根據返回的資料執行的程式碼  function showData(){
    document.body.innerHTML = data;
  }
  getData(showData);

2 回撥地獄

當一個回撥函式巢狀一個回撥函式的時候,就會出現一個巢狀結構,當巢狀的多了就會出現回撥地獄的情況, 比如我們傳送三個 ajax 請求,第一個正常傳送,第二個請求需要第一個請求的結果中的某一個值作為引數,第三個請求需要第二個請求的結果中的某一個值作為引數

ajax({
   url: '我是第一個請求',
   success (res) {
     // 現在傳送第二個請求     ajax({
       url: '我是第二個請求',
       data: { a: res.a, b: res.b },
       success (res2) {
         // 進行第三個請求         ajax({
           url: '我是第三個請求',
           data: { a: res2.a, b: res2.b },
           success (res3) {
               console.log(res3) ;
               // ...           }
         })
       }
     })
   }
 })

回撥地獄,其實就是回撥函式巢狀過多導致的,當程式碼成為這個結構以後,已經沒有維護的可能了,所以我們要把程式碼寫的更加的藝術一些。

3 Promise的使用

Promise是一個物件,這個物件有三個狀態:

  • 待定(pending):初始狀態,既沒有成功,也沒有失敗,表示非同步任務正在進行中
  • 成功(fulfilled):非同步任務執行完畢,變成成功狀態
  • 失敗(rejected):非同步任務執行完畢,變成失敗狀態

下面就帶大家建立一個Promise物件

let p1 = new Promise(function (resolve, reject) {
    // 此處執行非同步的程式碼    setTimeout(()=>{
        // 我們可以根據自己的標準在非同步任務完成的時候        // 選擇是執行失敗的回撥函式還是成功的回撥函式        // 第一個形參resolve 表示成功的回撥        resolve('300')
        // 第二個形參reject 表示失敗的回撥    },3000)})// 定義當p1這個promise物件變成成功狀態的時候要執行的回撥函式p1.then((data)=>{
    console.log("我是成功的時候執行的函式")
    console.log("我執行的時候你給我傳入的引數",data)})// 定義當p1這個promise物件變成失敗狀態的時候要執行的回撥函式p1.catch((err)=>{
    console.log("我是失敗的時候執行的函式")
    console.log("我執行的時候你給我傳入的引數",err)})


Promise物件這樣就建立好了,那小夥伴們趕緊自己試試吧!


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70023145/viewspace-2940164/,如需轉載,請註明出處,否則將追究法律責任。

相關文章