• JavaScript:Promise进阶知识


    Promise

    Promise就是ES6新增的一个用于解决异步编程的方案。以前,我们在处理异步的时候,都是在回调函数内做处理的。比如Ajax请求,是在success属性里面做异步处理的,那么如果在一个请求中需要执行读个异步请求,第二个请求是依赖于第一个请求的结果,这样就导致代码嵌套很深,可读性差、很难维护并且难以复用。

    那么Promise正好可以解决这样的问题,Promise有3种状态:pending、fulfilled和rejected。Promise在创建阶段是属于pending状态,接着状态只能有两种一个数fulfilled或者rejected,状态改变后就不能再发生变化了,例如:

    const promise = new Promise((resolve, rejected) => {
        // 异步请求处理
        if (/异步请求/) {
            resolve();
        } else {
            rejected();
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    异步请求成功,则执行resolve函数,否则执行rejected函数,resolve和rejected函数可以传参数,作为后面.then函数或者catch函数的数据源。

    Promise在创建后立即调用,然后等待执行resolve或者是rejected函数来确定Promise的最终状态,比如下面代码:

    const promise = new Promise((resolve, rejected) => {
        console.log("Promise");
        resolve();
    })
    
    promise.then(() => {
        console.log("resolve")
    });
    
    console.log("hello")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结果就是Promise,hello,resolve。因为Promise创建后会立即执行,输出Promise;然后是执行resolve函数,这样就会触发then函数里面的回调函数,但是它需要等待当前线程代码执行完毕后再执行,缩回跳过,先执行后面的代码,输出hello,最后执行then的回调函数,输出resolve。

    then函数,返回的是一个Promise对象实例,所以可以通过链式调用then函数,在上一个then函数内return的值是下一个then函数接收的数据,比如:

    const promise = new Promise((resolve, rejected) => {
        resolve(1);
    })
    
    promise.then((res) => {
        console.log(res);
        return 2;
    }).then(res => {
        console.log(res);
        return 3;
    }).then(res => {
        console.log(res)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    结果就是一次打印1,2,3。这样就是可以解决异步回调地狱的问题。

    catch函数,是Promise执行失败的回调。如果我们在Promise中手动抛出一个异常,来测试catch函数,代码如下:

    const promise1 = new Promise((resolve, rejected) => {
        try {
            throw new Error("测试");
        } catch (error) {
            rejected(error)
        }
    })
    
    promise1.catch(err=>{
        console.log(err); // Error: 测试
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    然而Promise在执行中,如果出现异常就会自动抛出,这样上面的代码可以改为:

    const promise1 = new Promise((resolve, rejected) => {
        throw new Error("测试");
    })
    
    promise1.catch(err=>{
        console.log(err); // Error: 测试
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    但是需要注意,Promise的状态一旦变味fulfilled成功状态,然后再抛出异常,是不能触发catch的,因为前面已经说过了Promise的状态只要发生变化后就不能再次更改。

    Promise静态方法

    Promise.all()函数

    将多个Promise对象实例包装成为一个Promise实例,参数是一个数组,这个Promise的状态是由所有传入Promise对象来决定,当所有的Promise的状态为fulfilled,这个新的Promise的状态才是fulfilled状态,如果有一个promise的状态为rejected,那么这个新Promise的状态就是reject。

    现在使用一段代码来理解上面的描述:

    const p1 = new Promise((resolve, reject) => {
        resolve("success")
    })
    
    const p2 = new Promise((resolve, reject) => {
        resolve(1)
    })
    
    const p = Promise.all([p1, p2]);
    p.then(res => {
        console.log(res);
    }).catch(err => {
        console.log(err)
    })
    // [ 'success', 1 ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    如果p1,p2中已经定义了对应的catch,当有一个promise状态变为reject的话,promise.all不会触发catch函数了,比如:

    const p1 = new Promise((resolve, reject) => {
        resolve("success")
    }).then(res => res).catch(err => err)
    
    const p2 = new Promise((resolve, reject) => {
        throw new Error("报错")
    }).then(res => res).catch(err => err)
    
    const p = Promise.all([p1, p2]);
    p.then(res => {
        console.log(res)
    }).catch(err => {
        console.log(err)
    })
    // [ 'success',  Error: 报错 ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    Promise.race 函数

    通过race方法来合并多个promise,那么这个promise状态是最先更新状态的promise的状态,比如:

    const p1 = new Promise((resolve, reject) => {
    }).then(res => res).catch(err => err)
    
    const p2 = new Promise((resolve, reject) => {
        reject("失败了")
    }).then(res => res).catch(err => err)
    const race = Promise.race([p1, p2]);
    race.then(res => {
        console.log(res)
    }).catch(err => {
        console.log(err)
    }) // 失败了
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    Promise.any函数

    传入一个可迭代的参数,如数组。
    结果为:
    1、所有promise状态都为成功,返回的是第一个promise的成功状态

    //1.获取轮播数据列表
    
    function getBannerList() {
        return new Promise((resolve, reject) => {
            resolve('banner')
        })
    }
    
    //2.获取店铺列表
    
    function getStoreList() {
        return new Promise((resolve, reject) => {
            resolve('store')
        })
    }
    
    //3.获取分类列表
    
    function getCategoryList() {
        return new Promise((resolve, reject) => {
            resolve("失败了")
        })
    }
    
    function initLoad() {
    
        Promise.any([getBannerList(), getStoreList(), getCategoryList()])
    
            .then(res => {
    
                console.log(res)
    
            }).catch(err => {
    
                console.log(err)
    
            })
    
    }
    initLoad(); // banner
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    2、有一个promise的状态为失败,那么就返回第一个状态为成功的promise:

    //1.获取轮播数据列表
    
    function getBannerList() {
        return new Promise((resolve, reject) => {
            reject('banner')
        })
    }
    
    //2.获取店铺列表
    
    function getStoreList() {
        return new Promise((resolve, reject) => {
            resolve('store')
        })
    }
    
    //3.获取分类列表
    
    function getCategoryList() {
        return new Promise((resolve, reject) => {
            resolve("失败了")
        })
    }
    
    function initLoad() {
    
        Promise.any([getBannerList(), getStoreList(), getCategoryList()])
    
            .then(res => {
    
                console.log(res)
    
            }).catch(err => {
    
                console.log(err)
    
            })
    
    }
    initLoad(); // store
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    3、所有promise状态为失败的,那么返回的是[AggregateError: All promises were rejected]:

    //1.获取轮播数据列表
    
    function getBannerList() {
        return new Promise((resolve, reject) => {
            reject('banner')
        })
    }
    
    //2.获取店铺列表
    
    function getStoreList() {
        return new Promise((resolve, reject) => {
            reject('store')
        })
    }
    
    //3.获取分类列表
    
    function getCategoryList() {
        return new Promise((resolve, reject) => {
            reject("失败了")
        })
    }
    
    function initLoad() {
    
        Promise.any([getBannerList(), getStoreList(), getCategoryList()])
    
            .then(res => {
    
                console.log(res)
    
            }).catch(err => {
    
                console.log(err)
    
            })
    
    }
    initLoad(); // [AggregateError: All promises were rejected]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
  • 相关阅读:
    Java基础篇:什么是hashCode 以及 hashCode()与equals()的联系
    一种结合白平衡统计信息和曝光信息的软光敏算法专利学习(专利三)
    Python 桌面程序教程之 04 持久窗口使用事件循环进行多次读取,更新窗口中的数据(教程含源码)
    【Linux】指针常量和常量指针
    Docker CI
    摄影构图:人像摄影和风景摄影的一些建议
    爱普生L125X_L325X系列打印机Wi-Fi配置方法(Smart Panel)
    C/C++ 使用 define 实现运行时函数是在哪个文件哪个函数被调用
    java spring cloud 企业工程管理系统源码+二次开发+定制化服务
    完美解决docker skywalking报错:no provider found for module storage
  • 原文地址:https://blog.csdn.net/xuelian3015/article/details/127604918