zoukankan      html  css  js  c++  java
  • 异步编程 -- Promise

    Promise

    为了解决回调函数经常出现的回调地狱问题,CommonJS社区提出了Promise的规范,最终在es2015中被标准化,成为语言规范

    Promise用来表示一个异步任务最终是成功还是失败,像是对任务作出的承诺,许下这个承诺后,任务进入到pending状态,等待承诺的兑现,然后等承诺兑现后,状态会根据结果发生改变,可能是成功,也可能是失败,但是不再可能是pending等待状态。当状态发生发往后,会执行相应状态的回调函数。

    Promise怎么使用?

    这里简单用Promise模拟一下ajax

    // Promise 方式的ajax
    function ajax(url){
      return new Promise(function(resolve,reject){
        var xhr=new XMLHttpRequest()
        xhr.open('GET',url)
        xhr.responseType='json'
        xhr.onload=function(){
          if(this.status===200){
            resolve(this.response)
          }else{
            reject(new Error(this.statusText))
          }
        }
        xhr.send()
      })
    }
    
    // 测试
    ajax('/api/foo.json')
    .then(function(res){
      console.log(res)
    })
    .catch(function(error){
      console.log(error)
    })
    

    Promise常见误区

    就拿上面例子举例,当我们从foo.json中获取到数据后,需要再从bar.json中继续获取数据,有时会把代码写成如下格式:

    ajax('/api/foo.json')
    .then(function(res){
      ajax('/api/bar.json')
      .then(function(res){
        console.log(res)
      }
    })
    

    这样写,还是形成了回调地狱,正确的写法可以是下面这样:

    ajax('/api/foo.json')
    .then(function(res){
      // 在这里处理数据
      // 。。。
    
      // 把第二个请求进行返回
      return ajax('/api/bar.json')
    })
    .then(function(res){
      // 这样当我们还需要再进行更多的请求的时候可以接着像刚才这样写
      console.log(res)
      return ajax('/api/other.json')
    })
    .then(function(res){
      console.log(res)
    })
    

    Promise 并行执行

    当多个请求之间并没有因为关系时,可以让其同时请求,即并行执行,使用Promise.all和Promise.race可以完成这一要求

    // Promise.all需要等全局请求都成功才能获取到结果,结果是一个数组,对应传入请求,失败一个就全部失败,进入catch
    var promiseOfAll = Promise.all([
      ajax('/api/foo.json'),
      ajax('/api/bar.json'),
      ajax('/api/other.json')
    ])
    promiseOfAll.then(function(values){
      // values是一个数组
      console.log(values)
    })
    .catch(function(error){
      console.log(error)
    })
    
    
    // Promise.race只等待第一个完成的请求,任何一个任务完成了,这个Promise就算完成了,全部失败才会进入catch
    var promiseOfRace = Promise.race([
      ajax('/api/foo.json'),
      ajax('/api/bar.json'),
      ajax('/api/other.json')
    ])
    promiseOfRace.then(function(value){
      console.log(value)
    })
    .catch(function(error){
      console.log(error)
    })
    
    

    Promise的静态方法

    // 通过resolve方法把常量转换成Promise对象
    Promise.resolve('foo')
    .then(function(value){
      console.log(value)
    })
    
    // 通过reject方法返回一个一定是失败的Promise对象,其传入的数据就是其失败的理由
    Promise.reject(new Error('rejected'))
    .catch(function(error){
      console.log(error)
    })
    

    Promise 执行时序

    如下例子:

    console.log('global start')
    setTimeout(()=>{
      console.log('setTimeout')
    },0)
    Promise.resolve()
    .then(()=>{
      console.log('promise')
    })
    .then(()=>{
      console.log('Promise2')
    })
    .then(()=>{
      console.log('Promise3')
    })
    console.log('end')
    

    输出结果:
    global start
    end
    Promise
    Promise2
    Promise3
    setTimeout

    结果分析:首先global start 和end是同步代码,会首先输出,其次是setTimeout和Promise都可以看作是宏任务,宏任务的回调可以是作为一个新的宏任务进入到队列中进行排队,也可以是作为微任务,紧跟着当前宏任务结束后立即执行,而Promise的then、catch、finally都是Promise的微任务,会在Promise之后立即执行,而setTimeout中的回调则是一个新的宏任务,会到队列的未尾重新排队,所以执行时序会靠后

  • 相关阅读:
    递归的一些应用(一)遍历文件夹
    获取指定路径下文件夹所有文件的大小
    JavaScript Color Picker
    在ASP.NET中,用javascript给CuteEditor控件赋值
    通过URL判断文件是否有存在
    语音验证码
    [链接].net 学习网站
    [音乐]梦中的婚礼
    [转载]天堂猎人影院的爱情狩猎
    为应用程序添加消息过滤器
  • 原文地址:https://www.cnblogs.com/MissSage/p/14880528.html
Copyright © 2011-2022 走看看