美文网首页vue
Promise是什么?一次性讲清楚

Promise是什么?一次性讲清楚

作者: 缺月楼 | 来源:发表于2019-06-05 17:27 被阅读0次

    Promise 的含义

    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

    所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

    Promise对象有以下两个特点。

    (1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

    (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

    有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。

    Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

    通俗来讲的话就是

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

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

    Promise 启动之后,当满足成功的条件时我们让状态从pending 变成 fullfilled(执行 resolve);当满足失败的条件,我们让状态从 pending 变成 rejected(执行reject
    就这么简单! 下面看代码 ,为什么会推出Promise它解决了那些痛点,提供了什么便利!

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

    有这么一个需求 :对于以上代码如何实现: 1秒钟之后输出 fn1, 再过1秒输出 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()
      })
    })
    

    这样一层一层的镶嵌,就形成了回调地狱!很难受,如果需要多次输出的话 ,人就崩溃了。终极解决方案

    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 启动之后,当满足成功的条件时我们让状态从pending 变成 fullfilled(执行 resolve);当满足失败的条件,我们让状态从 pending 变成 rejected(执行reject
    下面Promise可以理解为3秒之后返回一个承诺,随机输出一个1~7之间的整数!

    function fn(){
      return new Promise((resolve,reject)=>{ //必须要掌握这句
      setTimeout(()=>{
          let n = parseInt(Math.random() * 6 + 1 ,10 ) /*1~7之间的随机数,*/
          resolve(n)
      },3000)
    })
    }
    /*then()就是然后的意思    resolve(n)调用的时候会把会把传给then(x)中的第一个参数 `*/
    fn().then(
      (x) => { 
        console.log("随机数为"+x)
    },
      () => { 
        console.log("失败了")
    })
    

    Promise 范例

    Promise.prototype.then / Promise.prototype.catch

    Promise.prototype.then()

    Promise实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为Promise实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。

    then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。

    Promise.prototype.catch()

    Promise.prototype.catch方法是.then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

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

    相关文章

      网友评论

        本文标题:Promise是什么?一次性讲清楚

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