promise中鏈式調用then的問題

promise是一個很好的解決異步調用的方法,其鏈式調用也是一個很好的方式,這裏探究一下其調用過程

主要問題

Promise.resolve()
.then(res => {
  return new Promise()  
})

Promise.resolve()
.then(res => {
  new Promise()  
})

// 上下兩種Promise的方式中, 是否會進行下去,以及新產生的promise是否會被傳遞下去,或者說有什麼區別

測試代碼

每一句打印後面都輸出了時間戳,是爲了更好描述運行順序
測試代碼直接貼在下方,可以拿到瀏覽器中進行測試查看

;(function () {
  // fn1()
  // fn1_1()
  // fn2()
  // fn3()
  // fn4()
  // fn5()
  // fn6()
  // fn7()
  // fn8()
  // fn9()
})()

function fn1 () {
  console.log('start', new Date().getTime())
  new Promise(resolve => {
    console.log('11111', new Date().getTime())
    
  }).then(res => {
    console.log('22222', new Date().getTime())
    
  }).then(res => {
    console.log('33333', new Date().getTime())

  })
  console.log('end', new Date().getTime())
  
  /*
  start 1560165694777
  11111 1560165694787
  end 1560165694790
  */
}

function fn1_1 () { 
  console.log('start', new Date().getTime())
  new Promise(resolve => {
    console.log('11111', new Date().getTime())
    resolve()
    console.log('11111-1111', new Date().getTime())
  }).then(res => {
    console.log('22222', new Date().getTime())
    
  }).then(res => {
    console.log('33333', new Date().getTime())

  })
  console.log('end', new Date().getTime())
  
  /*
  start 1560166834093
  11111 1560166834106
  11111-1111 1560166834108
  end 1560166834110
  22222 1560166834115
  33333 1560166834119
  */
}

/*
通過前 fn1, fn1_1 兩個小例子可知,最開始的new Promise可能對我們進行干擾,
出現這種狀況的原因是,申明 new Promise的時候此時異步還未開始,所以我們
直接按照接下來的方式進行測試
*/

function fn2 () {
  console.log('start', new Date().getTime())
  Promise.resolve()
  .then(res => {
    console.log('11111', new Date().getTime())
    
  })
  .then(res => {
    console.log('22222', new Date().getTime())
    
  }).then(res => {
    console.log('33333', new Date().getTime())

  })
  console.log('end', new Date().getTime())
  
  /*
  start 1560166657107
  end 1560166657117
  11111 1560166657120
  22222 1560166657122
  33333 1560166657130
  */
}

function fn3 () {
  console.log('start', new Date().getTime())
  Promise.resolve()
  .then(res => {
    console.log('11111', new Date().getTime())
    
  }).then(res => {
    console.log('22222', new Date().getTime())
    return Promise.reject('2222error')
    
  }).then(res => {
    console.log('33333', new Date().getTime())

  }).catch(err => {
    console.log(err, new Date().getTime())
  })
  console.log('end', new Date().getTime())
  
  /*
  start 1560166779524
  end 1560166779533
  11111 1560166779537
  22222 1560166779539
  2222error 1560166779543
  */
}

/*
通過 fn3 這個例子知道了,只要在調用過程中,返回了一個Promise的reject狀態就會結束下去
*/

function fn4 () {
  console.log('start', new Date().getTime())
  Promise.resolve()
  .then(res => {
    console.log('11111', new Date().getTime())
    return new Promise((resolve, reject) => { console.log('inner Promise', new Date().getTime())})
  })
  .then(res => {
    console.log('22222', new Date().getTime())
    
  }).then(res => {
    console.log('33333', new Date().getTime())

  }).catch(err => {
    console.log(err, new Date().getTime())
  })
  console.log('end', new Date().getTime())
  
  /*
  start 1560167538395
  end 1560167538407
  11111 1560167538409
  inner Promise 1560167538414
  */
}

/*
通過 fn4 這個例子,如果調用鏈中返回一個pending,
他也會等待(Promise創建出來就是pending狀態),
他既沒有reject,也沒有resovle。

到目前,一共有兩種方式會阻止鏈式, 
① 返回了一個reject的Promise   
② 返回pendding狀態的Promsie
其餘的情況都會暢通無阻的運行下去(前提直接就在調用鏈中了)
*/

function fn5 () {
  console.log('start', new Date().getTime())
  Promise.resolve()
  .then(res => {
    console.log('11111', new Date().getTime())
    
  }).then(res => {
    console.log('22222', new Date().getTime())
    Promise.reject('2222error')  
    
  }).then(res => {
    console.log('33333', new Date().getTime())

  }).catch(err => {
    console.log(err, new Date().getTime())
  })
  console.log('end', new Date().getTime())
  
  /*
  start 1560166933856
  end 1560166933865
  11111 1560166933869
  22222 1560166933873
  33333 1560166933874
  (node:8196) UnhandledPromiseRejectionWarning: 2222error
  */
}

/*
通過 fn5 這個例子,其實那個新創建的Promise,並不屬於這個調用鏈,我們接着向下驗證
*/

function fn6 () {
  console.log('start', new Date().getTime())
  Promise.resolve()
  .then(res => {
    console.log('11111', new Date().getTime())
    
  }).then(res => {
    console.log('22222', new Date().getTime())
    Promise.reject('2222error').then().catch(err => console.log('inner' + err, new Date().getTime()))  
    
  }).then(res => {
    console.log('33333', new Date().getTime())

  }).catch(err => {
    console.log(err, new Date().getTime())
  })
  console.log('end', new Date().getTime())
  
  /*
  start 1560167831274
  end 1560167831292
  11111 1560167831296
  22222 1560167831301
  33333 1560167831307
  inner2222error 1560167831316
  */
}

/*
通過 fn6 我們已經知道了在調用鏈中,如果return 出一個Promise,那麼
它將屬於此調用鏈,否則就會有他自己的一個調用鏈
*/


function timeout(ms) { // 這裏模擬一個異步操作
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

function fn7 () {
  console.log('start', new Date().getTime())
  Promise.resolve()
  .then(res => {
    console.log('11111', new Date().getTime())
    return timeout(500)
    
  }).then(res => {
    console.log('22222', new Date().getTime())
    return timeout(500)
    
  }).then(res => {
    console.log('33333', new Date().getTime())
    return timeout(500)
    
  }).catch(err => {
    console.log(err, new Date().getTime())
    return timeout(500)

  })
  console.log('end', new Date().getTime())
  
  /*
  start 1560167223744
  end 1560167223759
  11111 1560167223764
  22222 1560167224274
  33333 1560167224779
  */
}

function fn8 () {
  console.log('start', new Date().getTime())
  Promise.resolve()
  .then(res => {
    console.log('11111', new Date().getTime())
    timeout(500)
    
  }).then(res => {
    console.log('22222', new Date().getTime())
    timeout(500)
    
  }).then(res => {
    console.log('33333', new Date().getTime())
    timeout(500)
    
  }).catch(err => {
    console.log(err, new Date().getTime())
    timeout(500)

  })
  console.log('end', new Date().getTime())
  
  /*
  start 1560168006937
  end 1560168006951
  11111 1560168006954
  22222 1560168006961
  33333 1560168006966
  */
}

function fn9 () {
  console.log('start', new Date().getTime())
  Promise.resolve()
  .then(res => {
    console.log('11111', new Date().getTime())
    timeout(500).then(res => { console.log('inner11111', new Date().getTime()) })
    
  }).then(res => {
    console.log('22222', new Date().getTime())
    timeout(500).then(res => { console.log('inner22222', new Date().getTime()) })
    
  }).then(res => {
    console.log('33333', new Date().getTime())
    timeout(500).then(res => { console.log('inner33333', new Date().getTime()) })
    
  }).catch(err => {
    console.log(err, new Date().getTime())
    timeout(500).then(res => { console.log('inner44444', new Date().getTime()) })

  })
  console.log('end', new Date().getTime())
  
  /*
  start 1560168109766
  end 1560168109775
  11111 1560168109778
  22222 1560168109781
  33333 1560168109785
  inner11111 1560168110281
  inner22222 1560168110288
  inner33333 1560168110291
  */
}

/*
最後通過 fn7, fn8, fn9 這三個例子中,以及傳入的時間,
確實印證了之前所說的,這裏用一副圖進行代替。

所以最爲關鍵的就是,在Promise的調用鏈中,關鍵要明白你新產生的這個 Promsie
是否添加到了這個調用鏈中
*/

總結圖示

Promise調用鏈

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章