专栏首页我是做APP开发的JS中Promise理解与应用

JS中Promise理解与应用

Promise 中文释义:许诺,允诺;希望。意指我答应你我会去做的,不管成功还是失败我肯定会做的。

1、基础介绍

PromiseES6一个新的特性,本身是个对象用于表示一个异步操作的最终完成 (或失败), 及其结果值。创建一个Promise对象:

var promise1 = new Promise(function(resolve, reject) {}  );

传入一个参数-函数function(resolve, reject) {},该函数本身两个参数也是函数。Promise执行构造函数时立即执行该函数function(resolve, reject) {},然后返回对象promise1。执行结果要么成功、要么失败:

  • 如果执行完成调用resolve ,promise1状态变为fulfilled 。
  • 如果失败调用reject,promise1状态变为rejected 。

Demo1——一个简单示例

//Demo1
var promise1 = new Promise(function(resolve, reject) {
    //这里通常执行一个异步任务比如网络数据请求等,成功返回调用resolve , 失败reject
    resolve('执行成功');
});

promise1.then(function(s){
    console.log('成功:' + s);
} , function(s){
    console.log("失败:"  + s);
})

//结果输出 成功:执行成功

所以可以理解为promise用不同的状态来标记事件不同的处理结果,当执行完成时状态为fulfilled , 失败时状态变为rejected。然后通过then方法绑定事件来处理不同的状态。

Promise有三种状态

pending: 初始状态,既不是成功,也不是失败状态。 fulfilled: 意味着操作成功完成。 rejected: 意味着操作失败。

状态变化只能有 pending-> fulfilled 或者 pending-> rejected 两种方式,一旦状态发生变化则保持固定不变。

2、方法介绍

then方法 ,原型 then(onFulfilled[, onRejected])

如上所述通过then方法对promise对象绑定处理事件 ,它最多需要有两个参数:Promise 的成功和失败情况的回调函数。 当成功时执行第一个参数onFulfilled的回调处理,失败执行第二个参数onRejected的回调处理,然后返回一个 新的Promise对象,然后可以继续添加then方法处理回调,以此可形成链式调用。

then方法是个很重要的方法,下面我们结合各种情况来示例说明

注意两个参数是可选的 如果调用 then 的 Promise 的状态(fulfillment 或 rejection)发生改变,但是 then 中并没有关于这种状态的回调函数,那么 then 将创建一个没有经过回调函数处理的新 Promise 对象,这个新 Promise 只是简单地接受调用这个 then 的原 Promise 的终态作为它的终态。

Demo2——then方法没有回调处理参数(无任何参数)

//demo2---then没有回调处理参数
var promise1 = new Promise(function(resolve, reject) {
    //这里通常一个异步任务比如网络数据请求等,成功返回调用resolve , 失败reject
    resolve('执行成功');
});

var promise2 = promise1.then()
promise2.then(function(v){
    console.log("v: " + JSON.stringify(v));
})

//或直接这样
/*promise1.then().then(function(v){
    console.log("v: " + JSON.stringify(v));
})*/

//输出 v: "执行成功"

新生成的对象promise2 状态直接是完成状态,接收上一级传递的参数,然后执行then中成功回调处理。

如果执行的reject('失败'),则会抛出一个错误异常,需要catch方法来捕获。

关于then返回值

当一个 Promise 完成(fulfilled)或者失败(rejected)时,返回函数将被异步调用(由当前的线程循环来调度完成)。具体的返回值依据以下规则返回。如果 then 中的回调函数:

  • 1、返回了一个值,那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
  • 2、没有返回任何值,那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined。
  • 3、抛出一个错误,那么 then 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
  • 4、返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
  • 5、返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
  • 6、返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。

Demo3——then方法中直接返回一个值

    //demo3---then直接返回一个值
    var promise1 = new Promise(function(resolve, reject) {
        //这里通常一个异步任务比如网络数据请求等,成功返回调用resolve , 失败reject
        resolve('执行成功');
    });
    
    var promise2 = promise1.then(
        function(value){
            return value;
        }
    )
    
    promise2.then(function(v){
        console.log("--v: " + JSON.stringify(v));
    })
    //输出--v: "执行成功"

then 回调总会返回一个promise对象,这个对象可以是隐式自动生成的,也可以是我们显示创建的。然后根据不同的状态在执行相应的回调处理。

catch方法 ,原型 catch(onRejected)

用于处理promise失败时错误捕获

Demo4——catch方法

    //demo4---catch方法
    var promise1 = new Promise(function(resolve, reject) {
        //这里通常一个异步任务比如网络数据请求等,成功返回调用resolve , 失败reject
        reject('执行失败');
    });
    
    var promise2 = promise1.then(function(value){
        console.log("执行成功" + value);//这里不会走到这里
    }/*,function(value){//如果放开这里,下面的catch 不会执行
        console.log('失败:' + value);
    }*/
        
    ).catch(function(err){
        console.log('err:' + err);
        return 'err promise'
    })
    
    console.log(promise2);

执行结果

image.png

如果then中有reject处理失败的回调,则不会执行catch。其实它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。 (事实上, calling obj.catch(onRejected) 内部calls obj.then(undefined, onRejected)).

所以可以理解为 catch()等价于 then(undefined, onRejected)) , 但是使用catch来处理错误更合适。因为它也可以处理then成功回调处理中抛出的错误。

可以看出catch中本身返回一个promise对象且状态已完成。如果 catch中抛出一个错误或返回一个本身失败的 Promise , 通过 catch() 返回的Promise 被rejected;否则,它将显示为成功(resolved)。

Promise.reject(reason)

生成一个状态已失败的promise对象

Promise.resolve(value)

生成一个状态已完成的promise对象

all(iterable) 方法

Promise.all(iterable)

参数iterable :一个包含至少一个promise对象的数组。

类似于与操作,必须全部执行完成才触发接下来的操作。

方法返回一个新的 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。

如果我们有多个异步任务处理,最后要监听全部执行完成,此时all方法就很合适。

race()

Promise.race(iterable) 参数iterable :一个包含至少一个promise对象的数组。

此类似于或操作,只要有一个完成或失败就算结束。任意一个子promise执行成功或失败后就会生成一个新的promise,状态就是第一个promise的状态。

Demo5—— race方法

    //race方法
    var promise1 = new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve('promise1 完成');
        } , 3000);
    })
    
    var promise2 = new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve('promise2 完成');
        } , 1500);
    })
    
    var promise3 = new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve('promise3 完成');
        } , 2000);
    })
    
    Promise.race([promise1,promise2,promise3]).then(function(value){
        console.log("value: " + JSON.stringify(value));
    })


//输出 value: "promise2 完成"

promise2最先执行,所以其执行完成后就结束流程。

常用的方法基本以上几个,剩下的就是结合实际场景应用了。

3、Promise常见应用

Demo6—— promise添加多个方法

    var promise1 = new Promise(function(resolve,reject){
        resolve('执行完成');
    })
    
    promise1.then(function(value){
        console.log('1----' + value);
    })
    
    promise1.then(function(value){
        console.log('2----' + value);
    })
    
    promise1.then(function(value){
        console.log('3----' + value);
    })

输出:

image.png

对同一个promise对象添加多个处理方法,就是相当于同时监听一个事件。

Demo7 ——监听多个异步任务全部完成

    var promise1 = new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log('promise1 完成');
            resolve('promise1 完成');
        } , 3000);
    })
    
    var promise2 = new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log('promise2 完成');
            resolve('promise2 完成');
        } , 1500);
    })
    
    var promise3 = new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log('promise3 完成');
            resolve('promise3 完成');
        } , 2000);
    })
    
    Promise.all([promise1,promise2,promise3]).then(function(value){
        console.log("value: " + JSON.stringify(value));
    })

输出结果:

image.png

all方法返回新的promise对象,回调处理函数参数和实际执行完成顺序无关,只和添加的顺序有关。

Demo8 ——实现链式操作 特别是一个异步任务请求数据要用于下一个任务操作的这种必须的先后次序总,尤为重要。

修改demo7要顺序执行:即依次输出promise1完成-promise2完成-promise3完成。

    var promise1 = new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log('promise1 完成');
            resolve('promise1 完成');
        } , 3000);
    }).then(function(value){
        return new Promise(function(resolve,reject){
            setTimeout(function(){
                console.log('promise2 完成');
                resolve('promise2 完成');
            } , 1500);
        });
        
        return p
    }).then(function(value){
        return new Promise(function(resolve,reject){
            setTimeout(function(){
                console.log('promise3 完成');
                resolve('promise3 完成');
            } , 2000);
        });
        
        return p
    })

此时promise1对象就是最后一个then方法返回的对象,状态为接受状态,并且该接受状态的回调函数的参数值为 promise3 完成

执行结果:

image.png

4、总结

  • promise一旦开始不能终止。
  • 状态一旦改变就固定了,不会在被修改。
  • 在异步操作中抛出错误异常无法被捕获。

Promise主要用于异步处理,根据不同的状态执行相应的回调处理,有点类似其他系统的状态机的概念

ok , 关于Promise的介绍到此结束,理解了这些在实际应用中为我们多任务的异步处理又多一种选择。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • OC 消息机制及转发

    这个错误提示几乎每个开发者都会遇到很多次,是由于给对象发送了一个无法识别的消息造成系统不能正常处理。

    Light413
  • Vue使用问题记录

    由于Vue将其插值渲染成div内部文本后,文本并不换行,换行符显示为一个空格。解决:

    Light413
  • iOS MDM详解(1)— 初识和深入

    MDM - Moblie Device Management 移动设备管理,目的就是让企业能够方便的管理 iPhone、Pad等移动设备。

    Light413
  • JS:你真的会用 Promise 吗?

    试想一下,有 3 个异步请求,第二个需要依赖第一个请求的返回结果,第三个需要依赖第二个请求的返回结果,一般怎么做?

    WEBJ2EE
  • 打开Promise的正确姿势

    引言 最近实践中需要用到大量的异步回调风格代码的编写,作者最近处于同步编程风格转为异步编程风格的状态。同时第一时间遇到了下面提到的代码,第一直觉就是该代码肯定有...

    IMWeb前端团队
  • Promise基础

    为了避免同时使用同步、异步调用可能引起的混乱问题,Promise在规范上规定 Promise的then只能使用异步调用方式 。

    elson
  • node.js的Promise对象的使用

    我们看到chenqionghe虽然是第一个执行,却是最后输出内容,因为设置了3秒后执行

    雪山飞猪
  • ES6之Promise用法详解

    本文主要对ES6的Promise进行一些入门级的介绍。要想学习一个知识点,肯定是从三个方面出发,what、why、how。下面就跟着我一步步学习吧~

    半指温柔乐
  • javascript之Promise对象知识点整理

    Promise规范https://promisesaplus.com/中对Promise的状态的定义:

    开发架构二三事
  • 【TypeScript 演化史 — 第五章】将 async/await 编译到 ES3/ES5 (外部帮助库)

    自2015年11 发布1.7版以来,TypeScript 已支持 async/await 关键字。编译器使用 yield 将异步函数转换为生成器函数。这意味着咱...

    Javanx

扫码关注云+社区

领取腾讯云代金券