异步:Promise

作者: 好奇男孩 | 来源:发表于2018-05-13 03:19 被阅读27次

    Promise 是一个对象,对象里存储一个状态,这个状态是可以随着内部的执行转化的,为以下三种状态之一:等待态(Pending)、完成态(Fulfilled)、拒绝态(Rejected)。

    一开始,我们先设置好等状态从 pending 变成 fulfilled 和 rejected 的预案(当成功后我们做什么,失败时我们做什么)。

    Promise 启动之后,当满足成功的条件时我们让状态从 pending 变成 fullfilled (执行 resolve);当满足失败的条件,我们让状态从 pending 变成 rejected(执行 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"
        })
    

    链式调用

    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('出现了错误', 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 对象都完成后再执行
    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 对象都完成后再执行
    Promise.race([p1, p2, p3]).then(data=>{
      console.log(data)
    })
    

    作用:解决回调地狱,也就是多层嵌套回调函数问题

    范例:

    • 实现: 1秒钟之后输出 fn1, 再过疫苗输出 fn2, 再过1秒输出 fn3
    //回调函数方法
    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 形式回调
    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回调

      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)=>{
            做事
            如果成功就调用 resolve
            如果失败就调用 reject
        })
    }
    
    var promise = ajax()
    promise.then(successFn, errorFn)
    

    在 Node.js中的应用

    回调函数的第一个参数,必须是错误对象err(如果没有错误,该参数就是null);原因是执行分成两段,在这两段之间抛出的错误,程序无法捕捉,只能当作参数,传入第二段

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

    相关文章

      网友评论

        本文标题:异步:Promise

        本文链接:https://www.haomeiwen.com/subject/jbekdftx.html