es6-promise

Promise 是 JavaScript 異步編程中的重要概念,異步抽象處理對象,是目前比較流行 Javascript 異步編程解決方案之一

回調(diào)函數(shù) / 回調(diào)地獄

1秒鐘之后輸出 fn1, 再過1秒輸出 fn2, 再過1秒輸出 fn3。
即當我們需要發(fā)送多個異步請求,并且每個請求之間需要相互依賴時。這時 我們以嵌套方式來解決。形成了所謂的 "回調(diào)地獄"。

function fn1(callback) {
  setTimeout(()=>{
    console.log('fn1')
    callback()
  }, 1000)
}

function fn2(callback) {
  setTimeout(()=>{
    console.log('fn2')
    callback()
  }, 1000)
}

function fn3() {
  setTimeout(()=>{
    console.log('fn3')
  }, 1000)
}



fn1(function(){
  fn2(function(){
    fn3()
  })
})

這種編碼方式有以下幾個問題

  • 代碼邏輯書寫順序與執(zhí)行順序不一致,不利于閱讀與維護。
  • 異步操作的順序變更時,需要大規(guī)模的代碼重構(gòu)。
  • 回調(diào)函數(shù)基本都是匿名函數(shù),bug 追蹤困難。

Promise 的使用

我們使用 Promise 可以以直觀的方式,來解決 "回調(diào)地獄"。
即 Promise 處理多個相互關(guān)聯(lián)的異步請求。

const promise = new Promise((resolve, reject) => {
       // 異步處理
       // 處理結(jié)束后、調(diào)用 resolve 或 reject
       // 如果成功就調(diào)用 resolve
       // 如果失敗就調(diào)用 reject
})

promise.then(successFn, errorFn)

Promise 是一個對象,對象里存儲一個狀態(tài),這個狀態(tài)是可以隨著內(nèi)部的執(zhí)行轉(zhuǎn)化的,為以下三種狀態(tài)之一:

  • 等待態(tài)(Pending)
  • 完成態(tài)(Fulfilled)
  • 拒絕態(tài)(Rejected)。

一開始,我們先設(shè)置好等狀態(tài)從 pending 變成 fulfilledrejected 的預(yù)案(當成功后我們做什么,失敗時我們做什么)。
Promise 啟動之后,當滿足 成功 的條件時我們讓狀態(tài)從 pending 變成 fullfilled (執(zhí)行 resolve);當滿足 失敗 的條件,我們讓狀態(tài)從 pending 變成 rejected(執(zhí)行 reject

使用 Promise 解決剛才的回調(diào)函數(shù)

function fn1() {
  return new Promise((resolve, reject)=>{
    setTimeout(()=>{
      console.log('fn1...')
      resolve()
    }, 1000)    
  })
}

function fn2() {
  return new Promise((resolve, reject)=>{
    setTimeout(()=>{
      console.log('fn2...')
      resolve()
    }, 1000)    
  })
}

function fn3() {
  return new Promise((resolve, reject)=>{
    setTimeout(()=>{
      console.log('fn3...')
      resolve()
    }, 1000)    
  })
}

function onerror() {
  console.log('error')
}

fn1().then(fn2).then(fn3).catch(onerror)

Promise 范例

Promise.prototype.then / Promise.prototype.catch

function getIp() {
  var promise = new Promise(function(resolve, reject){
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getIp', true)
    xhr.onload = function(){
      var retJson = JSON.parse(xhr.responseText)  // {"ip":"58.100.211.137"}
      resolve(retJson.ip)
    }
    xhr.onerror = function(){
      reject('獲取IP失敗')
    }
    xhr.send()
  })
  return promise
}

function getCityFromIp(ip) {
  var promise = new Promise(function(resolve, reject){
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getCityFromIp?ip='+ip, true)
    xhr.onload = function(){
      var retJson = JSON.parse(xhr.responseText)  // {"city": "hangzhou","ip": "23.45.12.34"}
      resolve(retJson.city)
    }
    xhr.onerror = function(){
      reject('獲取city失敗')
    }
    xhr.send()
  })
  return promise
}
function getWeatherFromCity(city) {
  var promise = new Promise(function(resolve, reject){
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getWeatherFromCity?city='+city, true)
    xhr.onload = function(){
      var retJson = JSON.parse(xhr.responseText)   //{"weather": "晴天","city": "beijing"}
      resolve(retJson)
    }
    xhr.onerror = function(){
      reject('獲取天氣失敗')
    }
    xhr.send()
  })
  return promise
}

getIp().then(function(ip){
  return getCityFromIp(ip)
}).then(function(city){
  return getWeatherFromCity(city)
}).then(function(data){
  console.log(data)
}).catch(function(e){
  console.log('出現(xiàn)了錯誤', e)
})

Promise.all

function getCityFromIp(ip) {
  var promise = new Promise(function(resolve, reject){
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getCityFromIp?ip='+ip, true)
    xhr.onload = function(){
      var retJson = JSON.parse(xhr.responseText)  // {"city": "hangzhou","ip": "23.45.12.34"}
      resolve(retJson)
    }
    xhr.onerror = function(){
      reject('獲取city失敗')
    }
    xhr.send()
  })
  return promise
}

var p1 = getCityFromIp('10.10.10.1')
var p2 = getCityFromIp('10.10.10.2')
var p3 = getCityFromIp('10.10.10.3')

//Promise.all, 當所有的 Promise 對象都完成后再執(zhí)行
Promise.all([p1, p2, p3]).then(data=>{
  console.log(data)
})

Promise.race

Promise.race 只要有一個 Promise對象 進入 FulFilled 或者 Rejected 狀態(tài)的話,就會繼續(xù)進行后面的處理。

function getCityFromIp(ip) {
  var promise = new Promise(function(resolve, reject){
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getCityFromIp?ip='+ip, true)
    xhr.onload = function(){
      var retJson = JSON.parse(xhr.responseText)  // {"city": "hangzhou","ip": "23.45.12.34"}
      resolve(retJson)
    }
    xhr.onerror = function(){
      reject('獲取city失敗')
    }
    setTimeout(()=>{
      xhr.send()
    }, Math.random()*1000)

  })
  return promise
}

var p1 = getCityFromIp('10.10.10.1')
var p2 = getCityFromIp('10.10.10.2')
var p3 = getCityFromIp('10.10.10.3')

//Promise.all, 當所有的 Promise 對象都完成后再執(zhí)行
Promise.race([p1, p2, p3]).then(data=>{
  console.log(data)
})
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 參考深入理解 Promise 五部曲 -- 1.異步問題[http://www.ghostchina.com/pr...
    合肥黑閱讀 2,432評論 0 14
  • Promise的含義: ??Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和...
    呼呼哥閱讀 2,270評論 0 16
  • 前言 在Promise之前,js的異步編程都是采用回調(diào)函數(shù)和事件的方式。但是這種編程方式在處理復(fù)雜業(yè)務(wù)的情況下,很...
    卓三陽閱讀 917評論 0 1
  • 我能猜透 多少的陰晴圓缺 一壺清酒 為你斟上四海五岳 花謝花開 春去秋來 眸子里是悲歡交錯的告別 攜來紙箋試...
    季逸澄閱讀 191評論 0 1
  • 山中徒步識植物 從成都坐上前往巴東的動車,窗外是陰雨與云霧繚繞的山頭,與以往任何一次的獨自旅行一樣,我又即將踏上未...
    青青禾閱讀 603評論 2 3

友情鏈接更多精彩內(nèi)容