異步:Promise

Promise 是一個對象,對象里存儲一個狀態(tài),這個狀態(tài)是可以隨著內(nèi)部的執(zhí)行轉(zhuǎn)化的,為以下三種狀態(tài)之一:等待態(tài)(Pending)、完成態(tài)(Fulfilled)、拒絕態(tài)(Rejected)。

一開始,我們先設置好等狀態(tài)從 pending 變成 fulfilled 和 rejected 的預案(當成功后我們做什么,失敗時我們做什么)。

Promise 啟動之后,當滿足成功的條件時我們讓狀態(tài)從 pending 變成 fullfilled (執(zhí)行 resolve);當滿足失敗的條件,我們讓狀態(tài)從 pending 變成 rejected(執(zhí)行 reject)

Promise 方法

Promise.prototype.then / Promise.prototype.catch

如何生成一個promise對象

   function A(){
        return new Promise (function(x,y){
            setTimeout(()=>{
                x("hello")
            }, 3000)
        })
    }
    A().then((e)=>{
        console.log(e)  //"hello"
    })

鏈式調(diào)用

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

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)
})

作用:解決回調(diào)地獄,也就是多層嵌套回調(diào)函數(shù)問題

范例:

  • 實現(xiàn): 1秒鐘之后輸出 fn1, 再過疫苗輸出 fn2, 再過1秒輸出 fn3
//回調(diào)函數(shù)方法
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()
  })
})

//Promise
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)
  • 把如下 ajax 改造成一個返回 Promise對象的方法
    改造前:jQuery 的 success / error 形式回調(diào)
function ajax(opts){
    var url = opts.url
    var type = opts.type || 'GET'
    var dataType = opts.dataType || 'json'
    var onsuccess = opts.onsuccess || function(){}
    var onerror = opts.onerror || function(){}
    var data = opts.data || {}

    var dataStr = []
    for(var key in data){
        dataStr.push(key + '=' + data[key])
    }
    dataStr = dataStr.join('&')

    if(type === 'GET'){
        url += '?' + dataStr
    }

    var xhr = new XMLHttpRequest()
    xhr.open(type, url, true)
    xhr.onload = function(){
        if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
            //成功了
            if(dataType === 'json'){
                onsuccess( JSON.parse(xhr.responseText))
            }else{
                onsuccess( xhr.responseText)
            }
        } else {
            onerror()
        }
    }
    xhr.onerror = onerror
    if(type === 'POST'){
        xhr.send(dataStr)
    }else{
        xhr.send()
    }
}

ajax({
    url: 'http://api.jirengu.com/weather.php',
    data: {
        city: '北京'
    },
    onsuccess: function(ret){
        console.log(ret)
    },
    onerror: function(){
        console.log('服務器異常')
    }
})

改造后:Promise回調(diào)

  function ajax(opts) {
        var url = opts.url
        var type = opts.type || 'GET'
        var dataType = opts.dataType || 'json'
        var data = opts.data || {}
        var dataStr = []

        for (var key in data) {
            dataStr.push(key + '=' + data[key])
        }

        dataStr = dataStr.join('&')

        if (type === 'GET') {
            url += '?' + dataStr
        }
        var promise = new Promise(function(resolve, reject){
            var xhr = new XMLHttpRequest()
            xhr.open(type, url, true)
            xhr.onload = function () {
                if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
                    //成功了
                    if (dataType === 'json') {
                        var ret = ( JSON.parse(xhr.responseText))
                        resolve(ret)
                    } else {
                        var ret = ( xhr.responseText)
                        resolve(ret)
                    }
                } else {
                    reject()
                }
            }
            if (type === 'POST') {
                xhr.send(dataStr)
            } else {
                xhr.send()
            }
        })
        return promise;
    }

    ajax({
        url: 'http://api.jirengu.com/weather.php',
        data: {
            city: '北京'
        }
    }).then(function(ret){
        console.log(ret)
    }).catch(function(){
        console.log('服務器異常')
    })

簡化版

function ajax(){
    return new Promise((resolve, reject)=>{
        做事
        如果成功就調(diào)用 resolve
        如果失敗就調(diào)用 reject
    })
}

var promise = ajax()
promise.then(successFn, errorFn)

在 Node.js中的應用

回調(diào)函數(shù)的第一個參數(shù),必須是錯誤對象err(如果沒有錯誤,該參數(shù)就是null);原因是執(zhí)行分成兩段,在這兩段之間拋出的錯誤,程序無法捕捉,只能當作參數(shù),傳入第二段

fs.readFile(fileA, 'utf-8', function (err, data) {
  fs.readFile(fileB, 'utf-8', function (err, data) {
    if (err) throw err;
  console.log(data);
  });
});
var readFile = require('fs-readfile-promise');

readFile(fileA)
.then(function (data) {
  console.log(data.toString());
})
.then(function () {
  return readFile(fileB);
})
.then(function (data) {
  console.log(data.toString());
})
.catch(function (err) {
  console.log(err);
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

  • Promise 對象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,834評論 1 56
  • 目錄:Promise 的含義基本用法Promise.prototype.then()Promise.prototy...
    BluesCurry閱讀 1,563評論 0 8
  • 00、前言Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大。它由社區(qū)...
    夜幕小草閱讀 2,226評論 0 12
  • Promiese 簡單說就是一個容器,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果,語法上說,Pr...
    雨飛飛雨閱讀 3,489評論 0 19
  • CABasicAnimation 父類是CAPropertyAnimation CABasicAnimation—...
    翻這個墻閱讀 359評論 0 0

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