zoukankan      html  css  js  c++  java
  • 【ES6】Promise用法

    ES6 - Promise用法

    参考:https://www.jianshu.com/p/7e60fc1be1b2

    https://www.jianshu.com/p/eb474a90cf46?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    Promise概念

    所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
    Promise对象有以下两个特点。
    (1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
    (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
    注意,为了行文方便,本章后面的resolved统一只指fulfilled状态,不包含rejected状态。
    有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
    
    此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
    Promise也有一些缺点。首先,无法取消Promise ,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise
    内部抛出的错误,不会反应到外部。第三,当处于pending
    状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
    如果某些事件不断地反复发生,一般来说,使用 Stream 模式是比部署Promise
    更好的选择。
    View Code

    Promise的构造函数接收一个参数(这个参数是一个函数),并且传入两个参数:resolve ,reject 分别表示异步操作执行成功后的回调函数
    和异步执行失败后的回调函数。其实这里用‘成功’,‘失败’ 来描述并不准确,按照标准来讲,resolve 是将Promise的状态置为fullfiled
    reject是将Promise的状态置为rejected。

    01、基本用法
    ES6 规定,Promise对象是一个构造函数,用来生成Promise实例

    Promise的基本结构 

    一步步的加载造成 回调地狱

        /*  //这种一步一步的加载 会造成回调地狱
         var img=new Image();
          img.src="./img/3-.jpg";
          img.onload=function () {
               var img=new Image();
               img.src="./img/4-/jpg";
               img.onload=function () {
                  var img=new Image();
                  img.src="./img/5-/jpg";
                  img.onload=function () {
                      var img=new Image();
                      img.src="./img/6-/jpg";
               }
               }
          }*/

    基本结构:

    /*var promise = new Promise(function (resolve, reject) {
            var img = new Image();
            img.src = "./img/3-.jpg";
            img.onload = function () {
                //加载成功,resolve(this) 传参数this
                resolve(this);
            };
            img.onerror = function () {
                //加载失败
                reject("加载失败");
            }
        });
        //此处是实例化了promise,也可以直接 .then() 连接
        promise.then(function (data) {
            console.log(data, "__________");
        }, function (error) {
            console.log(error, "========");
        })*/
    function loadImg(src) {
            return new Promise(function (res, rej) {
                var img = new Image();
                img.onload = function () {
                    res(this);
                };
                img.onerror = function () {
                    rej("加载错误");
                };
                img.src = src;
            });
        }
    
        var arr = [];
        loadImg("./img/3-.jpg").then(function (data) {
            arr.push(data);
            return loadImg("./img/4-.jpg");
        }, function (error) {
            console.log(error);
        }).then(function (data) {
            console.log(data);      //<img src='./img/4-.jpg'>
            arr.push(data);
            console.log('arr===>',arr);
        }, function (error) {
            console.log(error);
        })
    一张张的加载图片

    异步加载图片

    function getImage(src) {
                return new Promise(function (res,rej) {
                    let img=new Image();
                    img.src=src;
                    img.onload=function () {
                        //加载成功
                        res(img);
                    };
                    img.onerror=function () {
                        //加载错误
                        rej("加载错误")
                    }
                })
            }

     实例化一个对象

    /*let promise=getImage("./img/3-.jpg");
            let promise1=promise.then(res => {
                console.log(this);
                console.log('res--->',res);
                return getImage("./img/4-.jpg");
            },rej=> {
                console.log(rej);
            });
            let promise2=promise1.then(res=> {
                console.log(this);
                console.log(res);
                return getImage("./img/5-.jpg")
            });
            let promise3=promise2.then(res=> {
                console.log(this);
                console.log(res);
                return getImage("./img/6-.jpg")
            });*/

    链式异步

    /*
            *  链式异步
            *
            * */
            /*getImage("./img/3-.jpg").then(function (data) {
                console.log(this);
                console.log(data);
                return getImage("./img/4-.jpg");
            }).then(res=> {
                console.log(this);
                console.log(res);
                return getImage("./img/5-.jpg");
            }).then(function (data) {
                console.log(this);
                return getImage("./img/6-.jpg")
            })*/

     .then(res=>{},rej=>{})

    /*  then有两个参数,都是函数,第一个函数是成功调用函数,第二个函数是失败调用函数
                  getImage("./img/1-.jpg").then(function (data) {
                      console.log(data);
                  },function (err) {
                      console.log(err);
                  })*/
            //  catch :失败后执行方法,有一个参数,这个参数是函数,失败后执行
            /* getImage("./img/1-.jpg").then(function (data) {
                 console.log(data);
             }).catch(function (err) {
                 console.log(err);
             })*/

    Promise.all 执行多个异步数组。成功返回所有结果组成列表数组,失败的时候则返回最先被reject失败状态的值。

    /*
            * Promise.all  执行多个异步数组。成功返回所有结果组成列表数组,失败的时候则返回最先被reject失败状态的值。
            *
            * */
            let list = [];
            for (let i = 3; i < 80; i++) {
                list.push(getImage("./img/" + i + "-.jpg"));
            }
            
           /*Promise.all(list).then(function (arr) {
               console.log(arr);
               arr.forEach(t=>console.log(t.src));
           });*/

    Promse.all在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。

    代码模拟:

    let wake = (time) => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(`${time / 1000}秒后醒来`)
        }, time)
      })
    }
    
    let p1 = wake(3000)
    let p2 = wake(2000)
    
    Promise.all([p1, p2]).then((result) => {
      console.log(result)       // [ '3秒后醒来', '2秒后醒来' ]
    }).catch((error) => {
      console.log(error)
    })
    需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。

    Promise.race

    顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

    /*
            *   race  赛跑
            *   执行多个异步数组,谁先完成异步,返回谁
            *
            *
            * */
    
            Promise.race(list).then(function (data) {
                console.log(data);
            })
    let p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('success')
      },1000)
    })
    
    let p2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('failed')
      }, 500)
    })
    
    Promise.race([p1, p2]).then((result) => {
      console.log(result)
    }).catch((error) => {
      console.log(error)  // 打开的是 'failed'
    })

    应用举例:微信小程序 异步调用微信地图API

    <!--form表单-->
    <form bindsubmit="formSubmit">
        <!--输入起点和终点经纬度坐标,格式为string格式-->
        <label>起点坐标:
          <input style="border:1px solid #000;" name="start" value="鼓楼"></input>
        </label>
        <!--多个终点位置示例:39.984060,116.307520;39.984060,116.507520-->
        <label>终点坐标:
          <input style="border:1px solid #000;" name="dest"value="火车站"></input>
        </label>
        <!--提交表单数据-->
        <button form-type="submit">计算距离</button>
    </form>
    
    <!--渲染起点经纬度到终点经纬度距离,单位为米-->
    <view wx:for="{{distance}}" wx:key="index">
        <view>起点到终点{{index+1}}的步行距离为{{item}}米</view>
    </view>
    map-distance.wxml
    import myPromise from '../../utils/myPromise.js'
    import calculatePromise from '../../utils/calculatePromise.js'
    
    Page({
      /**
       * 页面的初始数据
       */
      data: {
        distance: [],
        startPos:{},
        destPos:{}
      },
    
      //在Page({})中使用下列代码
      //事件触发,调用接口
      formSubmit(e) {
        //将输入的地名转化为经纬度
        const startPlace = e.detail.value.start
        const destPlace = e.detail.value.dest
        
        myPromise({addr:startPlace}).then(res=>{
          console.log(res)
          this.setData({
            startPos: res.result.location
          })
        }).then(
          myPromise({ addr: destPlace }).then(res => {
            console.log(res)
            this.setData({
              destPos: res.result.location
            })
          })
        ).then(res2 => {
          console.log('===>', this.data)
          const newStartPos = `${this.data.startPos.lat},${this.data.startPos.lng}`
          const newDestPos = `${this.data.destPos.lat},${this.data.destPos.lng}`
          console.log(newStartPos,newDestPos)
          calculatePromise({ start: newStartPos, dest: newDestPos }).then(res => { //成功后的回调
              console.log('计算距离的成功回调::', res);
              var res = res.result;
              var dis = [];
              for (var i = 0; i < res.elements.length; i++) {
                dis.push(res.elements[i].distance); //将返回数据存入dis数组,
              }
              this.setData({ //设置并更新distance数据
                distance: dis
              });
            }
          )
        })
        
        
      }
    
    
    })
    mao-distance.js
    // 引入SDK核心类
    var QQMapWX = require('../libs/qqmap-wx-jssdk.js');
    
    // 实例化API核心类
    var qqmapsdk = new QQMapWX({
      key: '2BJBZ-TKDRU-NVMV4-2JAJC-VK2Y2-M7F3D' // 必填
    });
    
    export default function calculatePromise(options) {
      return new Promise((resolve, reject) => {
          //调用距离计算接口
          qqmapsdk.calculateDistance({
            //mode: 'driving',//可选值:'driving'(驾车)、'walking'(步行),不填默认:'walking',可不填
            //from参数不填默认当前地址
            //获取表单提交的经纬度并设置from和to参数(示例为string格式)
            from: options.start || '', //若起点有数据则采用起点坐标,若为空默认当前地址
            to: options.dest, //终点坐标
            success: resolve,
            fail:reject
          });
      })
    }
    calculatePromise.js
    // 引入SDK核心类
    var QQMapWX = require('../libs/qqmap-wx-jssdk.js');
    
    // 实例化API核心类
    var qqmapsdk = new QQMapWX({
      key: '2BJBZ-TKDRU-NVMV4-2JAJC-VK2Y2-M7F3D' // 必填
    });
    
    export default function myPromise(options) {
      return new Promise((resolve, reject) => {
        //解析地名 并转化为经纬度
        qqmapsdk.search({
          keyword: options.addr,
          success: res1 => {
            console.log('地名查询--->', res1);
            const address = res1.data[0].address
    
            qqmapsdk.geocoder({
              address: address,
              success: resolve,
              fail: reject
            })
          }
        })
      })
    }
    myPromise.js
  • 相关阅读:
    JQ和Js获取span标签的内容
    JS获取子节点、父节点和兄弟节点的方法实例总结
    JS实现系统时间(自动)
    CSS font-family 属性
    网页中导入特殊字体@font-face属性详解
    ****HTML模板资源汇总
    ***XAMPP:报错 Unable to load dynamic library的解决方法
    2016年宜昌楼市将迎来史上最激烈一战
    北大资源重磅来宜--宜昌未来商业中心将诞生
    HTML5调用传感器的资料汇总
  • 原文地址:https://www.cnblogs.com/XJT2018/p/11261089.html
Copyright © 2011-2022 走看看