zoukankan      html  css  js  c++  java
  • ES6语法——Promise对象

    一、概念

      Promise是异步编程的一种解决方案(解决回调地狱的问题),是一个能够获取异步操作信息的对象。Promise的内部保存着某个未来才会结束的事件(通常是一个异步操作)

    二、特点

      1.Promise对象的状态不受外界影响

        Promise对象的状态由异步操作的结果决定当前处于pending(进行中)、fulfilled(已成功)还是rejected(已失败),任何其他操作都无法改变这个状态。

      2.状态改变不可逆

        一旦状态改变,就不会再变,任何时候都可以得到这个结果。promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对promise对象添加回调函数,也会立即得到这个结果。

      3.缺点

        (1)无法取消promise,一旦新建它就会立即执行,无法中途取消

        (2)如果不设置回调函数,promise内部抛出的错误,不会反应到外部

        (3)当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

      4.优点

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

    三、基本用法 

      Promise对象是一个构造函数,接受一个函数为参数,这个函数的参数是resolve和reject,它们两个也是函数。

      resolve函数的作用是,将promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去,外部用then方法接收

      reject函数的作用是,将promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去,外部用catch方法接收

    const promise = new Promise(function(resolve, reject) {
      // ... some code
    
      if (/* 异步操作成功 */){
        resolve(value);
      } else {
        reject(error);
      }
    });
    

    四、API详解

      1.promise.prototype.then()

        then方法是定义在原型对象promise.prototype上的,它是异步操作成功的回调函数,是resolve函数的外部接收器。参数是一个函数。

        工作原理:当promise对象执行异步操作成功时,会通过resolve函数向外传递操作结果,由then方法接收后,对该结果继续执行传入then方法内部的函数。

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

    function async(a,b) {
        return new Promise(function (resolve,reject) {
            //异步代码
            setTimeout(function () {
                //加入数据格式的判断
                if(a!=undefined && (typeof a) =="number"){
                    //如果数据格式正确 则调用resolve匹配外部的then
                    resolve(a+b);
    
                }else{
                    //数据格式错误 调用reject  匹配外部的catch
                    reject(new Error("a is not a number,你瞎啊!!!"));
    
                }
    
            },200)
        });
        
    }
    var promise=async(1,2);
    promise.then(function (res) {
        if(res>2){  
            console.log("我是3分支");
          return async(res,3)
        }
    
        //如果上一个then返回了一个promise 那么可以后面继续跟着then
    }).then(function (res) {
        if(res>4){
            console.log("我是4分支");
            return async(res,4);
        }
        
    })
    

      2.promise.prototype.catch()

        catch方法的使用、原理同then方法,只是catch方法是失败的回调函数。

        注意:

          (1)如果没有使用catch()方法指定错误处理的回调函数,promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。

          (2)catch方法只能有一个,有多个无意义,后面的catch并不会执行,catch方法通常写在最后

    var user=new User("niujinghui","123456");
    user.checkUsername()
    .then(function (res) {
        return user.checkUserpwd();
    })
     .then(function (res) {
            console.log("用户名密码都正确");
    })
    .catch(function (err) {
        if(err) throw err;
    });
    

      3.promise.prototype.finally()

        finally()方法用于指定不管 promise 对象最后状态如何,都会执行的操作。该方法是 es2018 引入标准的。

    promise
    .then(result => {···})
    .catch(error => {···})
    .finally(() => {···});
    

        上面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。

       finally方法源码

    Promise.prototype.finally = function (callback) {
      let P = this.constructor;
      return this.then(
        value  => P.resolve(callback()).then(() => value),
        reason => P.resolve(callback()).then(() => { throw reason })
      );
    };
    

      4.promise.all()

        promise.all()用于将多个Promise实例包装成一个新的Promise实例。接受一个数组作为参数,如果该数组的元素不是promise对象实例,则使用Promise.resolve()方法将参数转为Promise实例再处理。另外,promise.all()方法的参数可以不是数组,但必须具有 iterator 接口,且返回的每个成员都是 promise 实例。

    const p = Promise.all([p1, p2, p3]);
    

        上面代码中p的状态由p1、p2、p3决定,有以下两种情况:

          (1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。(都成功,传返回值数组,如果没有返回值,会组成元素为undefined的数组)

          (2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。(一失败,传reject的返回值)

        注意!!坑点来袭

          1、如果作为参数的 promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发promise.all()的catch方法。如果没有自己的catch方法,就会调用promise.all()的catch方法。

          2、使用all()方法时,传入的promise对象如果本身定义了then和catch方法,因为这两个方法都会返回一个新的promise实例,所以调用all方法得到的新promise状态一直都是成功。解释起来有点绕,结合下面的代码看就知道了。

    const p1 = new Promise((resolve,reject)=>{
    	let abc = 10
    	let a = 10;
    	let b = 20
    	if(abc > 30){
    		resolve(a+b) 
    	}else{
    		reject(b-a) 
    	}
    }).then(function(res){
    	return res
    }).catch(function(err){
    	console.log(err)
    })
    const p2 = new Promise((resolve,reject)=>{
    	let abc = 10
    	let a = 10;
    	let b = 20
    	if(abc > 30){
    		resolve(a+b+b) 
    	}else{
    		reject(b-a-a) 
    	}
    }).then(function(res){
    	return res
    }).catch(function(err){
    	console.log(err)
    })
    const p3 = new Promise((resolve,reject)=>{
    	let abc = 10
    	let a = 10;
    	let b = 20
    	if(abc > 30){
    		resolve(a*b) 
    	}else{
    		reject(b/a) 
    	}
    }).then(function(res){
    	return res
    }).catch(function(err){
    	console.log(err)
    })
    
    const p=Promise.all([p1,p2,p3])
    p.then(function(){
    	console.log("正确")
    }).catch(function(){
    	console.log("错误")
    })
    

        上面的代码在abc的值小于30时,就会执行reject方法,当调用promise.all()时,应该会输出错误。但是因为p1、p2、p3都有各自的then和catch方法,返回了新的promise实例,又因为这个新实例已经处于完成状态,所以变量p才会一直处于成功状态。(小炉写代码的时候还思考了好久,大坑!!!)

      5.promise.race()

    const p = Promise.race([p1, p2, p3]);

        race方法的参数以及对参数中非promise对象的处理都和all方法一致,但是race方法返回的状态只和数组中最先改变状态的实例相同,那个最先改变的 promise 实例的返回值,就传递给p的回调函数。

        注意:

          (1)如果数组里面promise实例执行的速度一样,返回数组第一个promise执行的结果

          (2)如果数组里面promise实例执行的速度不一样,返回最快的promise执行的结果,结果是失败就会直接匹配race的catch方法

          (3)如果数组里面promise实例有成功、有失败的只要不是返回的结果,失败的就不影响

      6.promise.allsettled()

        promise.allsettled()方法接受一组 promise 实例作为参数,包装成一个新的 promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束。该方法由 es2020 引入。

        该方法返回的新的 promise 实例,一旦结束,状态总是fulfilled,不会变成rejected

    const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
    const results = await Promise.allSettled(promises);
    
    // 过滤出成功的请求
    const successfulPromises = results.filter(p => p.status === 'fulfilled');
    
    // 过滤出失败的请求,并输出原因
    const errors = results
      .filter(p => p.status === 'rejected')
      .map(p => p.reason);
    

      7.promise.any()

        promise.any()跟promise.race()方法很像,只有一点不同,就是不会因为某个 promise 变成rejected状态而结束。如果所有的promise实例都是rejected,则返回AggregateError: All promises were rejected

        经过小炉自己试验,总结规则如下:

          (1)如果数组里面promise实例执行的速度不一样,执行最快的promise结果为成功则返回,为失败则按照这个规则找第二快的,依次类推。

          (2)如果数组里面promise实例执行的速度一样,则返回第一个成功的promise的返回值

      8.promise.resolve()

        作用:将现有对象转为 Promise 对象

        参数情况:

          (1)参数是一个 Promise 实例

            如果参数是 promise 实例,那么promise.resolve将不做任何修改、原封不动地返回这个实例。

          (2)参数是一个thenable对象

            thenable对象指的是具有then方法的对象,promise.resolve方法会将这个对象转为 promise 对象,然后就立即执行thenable对象的then方法

    let thenable = {
      then: function(resolve, reject) {
        resolve(42);
      }
    };
    
    let p1 = Promise.resolve(thenable);
    p1.then(function(value) {
      console.log(value);  // 42
    });
    

           上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42。   

          (3)参数不是具有then方法的对象,或根本就不是对象

             如果参数是一个原始值,或者是一个不具有then方法的对象,则promise.resolve方法返回一个新的 promise 对象,状态为resolved。

          (4)不带有任何参数

             promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的 promise 对象。

      9.promise.reject()

        promise.reject(reason)方法也会返回一个新的 promise 实例,该实例的状态为rejected。

    const p = Promise.reject('出错了');
    // 等同于
    const p = new Promise((resolve, reject) => reject('出错了'))
    
    p.then(null, function (s) {
      console.log(s)
    });

        注意:promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与promise.resolve方法不一致。

    五、总结

      1.promise的作用:Promise是异步编程的一种解决方案(解决回调地狱的问题)

      2.无法取消promise,一旦新建它就会立即执行,无法中途取消

      3.如果不设置回调函数,promise内部抛出的错误,不会反应到外部

      4.当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

      5.promise.then()成功的回调函数,返回的是一个新的promise实例,可以使用链式编程,参数来自resolve函数

      6.promise。catch()失败的回调函数,只写一个,多写无意义,通常写在最后,参数来自reject函数

      7.promise.all()监听所有的promise实例状态,全成功则成功,一失败则失败

      8.promise.allsettled()监听所有的promise实例状态,等到所有这些参数实例都返回结果才结束,结束时状态总是fulfilled,不会变成rejected

      9.promise.any()不会因为某个 promise 变成rejected状态而结束。如果所有的promise实例都是rejected,则返回AggregateError: All promises were rejected

      10.promise.race()返回的状态只和数组中最先改变状态的实例相同,那个最先改变的 promise 实例的返回值,就传递给p的回调函数。

      11.promise.finally()不管 promise 对象最后状态如何,都会执行的操作

      12.promise.resolve()和promise.reject()都返回一个promise实例,但是promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数

  • 相关阅读:
    VS调试错误:若要调试此模块,请将其项目生成配置更改为"调试"模式
    Silverlight与常用数据库互操作系列索引
    aspnet在IIS注册
    arcgis server进行查询任务时默认返回最大为500条记录的修改方法
    【转】SQL Server 阻止了对组件 'Ad Hoc Distributed Queries' 的 STATEMENT'OpenRowset/OpenDatasource' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭
    【转】VS2008 使用小技巧 提高编程效率
    【转】C#复制、粘贴文本信息到剪贴板
    【转】使用sp_executesql执行动态SQL语句,同时向里面传入参数。
    【转】ASP.NET弹出对话框后网页变形解决办法
    你应该知道的Virtual Studio 2008
  • 原文地址:https://www.cnblogs.com/spoem/p/13329703.html
Copyright © 2011-2022 走看看