谈谈我对Promise的理解

一 、Promise

(一)Promise三种状态

Promise是ES6中提供的一个异步编程的解决方案,Promise本身是一个构造函数。

console.log(typeof Promise) // function

在JavaScript中,所有的代码都是同步执行的,而在js在进行网络操作,浏览器实践,任务队列时,就导致很多代码必须要进行回调,出现回调地狱。

ajax就是典型的异步操作。
Promise则是异步编程的一种解决方案,它有两个特点:
(1)对象的状态不受外界影响
(2)状态是不可逆不可改变

resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的
错误,作为参数传递出去。

Promise一共有三种状态,分别是:

  • pending [待定] 初始状态
  • fulfilled [实现] 操作成功
  • rejected [被否决] 操作失败

初始状态为pending,如果成功则resolved,如果失败测reject。

当promise状态发生改变,就会触发then()里的响应函数处理后续步骤;
promise状态一经改变,不会再变。
Promise对象的状态改变,只有两种可能:
从pending变为Resolved
从pending变为rejected。

Promise 的基本用法:

let promise = new Promise((resolve, reject) => {
	resolve()
}).then(res => {console.log(res)})

Pomise构造函数resolve()和reject()接收的函数作为参数,该函数有两个参数分别为resolve和reject,调用resolve则会代表成功,调用reject则会代表无效。

class Promise {
    constructor(executor) {
        this.status = "pending"; // 默认状态
        this.value;  // resolve 成功时的值
        this.error;  // reject 失败时的值

        let resolve = res => {
            if(this.status === "pending") {
                this.value = res;
                this.status = "resolved";
            }
        }

        let reject = err => {
            if(this.status === "pending") {
                this.error = err;
                this.status = "rejected";
            }
        }

        executor(resolve, reject);
    }
}

1、pending [待定] 初始状态

测试一下,如果不去resolve,也不去reject

// 测试一下:
new Promise((resolve, reject) => {
    
})

那么Promise应该是初始状态。我们将上面的代码执行测试一下,得到结果如下:
在这里插入图片描述
此时状态是:{status: “pending”}。

2、fulfilled [实现] 操作成功

当我们执行 resolve

// 测试一下:
new Promise((resolve, reject) => {
   resolve('成功啦~'); 
})

在这里插入图片描述
此时状态是:{status: “resolve”}。

3、rejected [被否决] 操作失败

当执行reject

// 测试一下:
new Promise((resolve, reject) => {
    resolve('失败啦~')
})

在这里插入图片描述
此时状态是:{status: “reject”}。

这里举一个类比的例子来加深对Promise的理解:
在这里插入图片描述
有一女朋友对男朋友许下承诺(new Promise)要怀孕,生个胖嘟嘟的孩子,对于该承诺是否兑现就有两种情况:
(1)resolve实现承诺,成功换上了孩子,进入then;
(2)reject没有实现承诺,在约定时间内没有成功怀孕,进入catch,返回错误信息 ;
不过不管有没有怀孕成功,最后,他们两个都会成功结婚。

代码如下:

const isPregnant = false;
const promise = new Promise((resolve, reject) => {
    if (isPregnant) {
        resolve('孩子他爹');
    } else {
        reject('老公');
    }
});

Promise
    .then(name => {
        console.log(`男人成为了${name}!`);
    })
    .catch(name => {
        console.log(`男人成为了${name}!`);
    })
    .finally(() => {
        console.log(`男人和女人最终结婚了!`);
    });

(二)、基于Promise处理多次Ajax请求(链式调用)【重要】

1、ajax多次链式调用

实际开发中,我们经常需要同时请求多个接口。比如说:在请求完接口1的数据data1之后,需要根据data1的数据,继续请求接口2,获取data2;然后根据data2的数据,继续请求接口3。

这种场景其实就是接口的多层嵌套调用。有了 promise之后,我们可以把多层嵌套调用按照线性的方式进行书写,非常优雅。

也就是说:Promise 可以把原本的多层嵌套调用改进为链式调用。

代码举例:(多次 Ajax请求,链式调用)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise</title>
</head>
<body>
    <script type="text/javascript">
        function queryData(url) {
            var promise = new Promise((resolve, reject) => {
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function() {
                    if (xhr.readyState != 4) return;
                    if (xhr.readyState == 4 && xhr.status == 200) {
                        resolve(xhr.responseText);
                    } else {
                        reject('接口请求失败');
                    }
                };
                xhr.responseType = 'json';
                xhr.open('get', url);
                xhr.send(null);
            });
            return promise;
        }

        queryData('http://localhost:3000/api1')
            .then(
                data1 => {
                    console.log(JSON.stringify(data1));
                    return queryData('http://localhost:3000/api2');
                },
                error1 => {
                    console.log(error1);
                }
            )

        .then(
                data2 => {
                    console.log(JSON.stringify(data2));
                    return queryData('http://localhost:3000/api3');
                },
                error2 => {
                    console.log(error2);
                }
            )
            .then(
                data3 => {
                    console.log(JSON.stringify(data3));
                },
                error3 => {
                    console.log(error3);
                }
            );
    </script>

</body>

</html>

2、 return 的函数返回值

return 后面的返回值,有两种情况:

情况1:返回 Promise 实例对象。返回的该实例对象会调用下一个 then。

情况2:返回普通值。返回的普通值会直接传递给下一个then,通过 then 参数中函数的参数接收该值。

3、Promise 的常用API:实例方法【重要】

Promise 自带的API提供了如下实例方法:

promise.then():获取异步任务的正常结果。

promise.catch():获取异步任务的异常结果。

promise.finaly():异步任务无论成功与否,都会执行。

代码如下:

写法一:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script>
            function queryData() {
                return new Promise((resolve, reject) => {
                    setTimeout(function() {
                        var data = { retCode: 0, msg: 'qianguyihao' }; // 接口返回的数据
                        if (data.retCode == 0) {
                            // 接口请求成功时调用
                            resolve(data);
                        } else {
                            // 接口请求失败时调用
                            reject({ retCode: -1, msg: 'network error' });
                        }
                    }, 100);
                });
            }
 
            queryData()
                .then(data => {
                    // 从 resolve 获取正常结果
                    console.log('接口请求成功时,走这里');
                    console.log(data);
                })
                .catch(data => {
                    // 从 reject 获取异常结果
                    console.log('接口请求失败时,走这里');
                    console.log(data);
                })
                .finally(() => {
                    console.log('无论接口请求成功与否,都会走这里');
                });
        </script>
    </body>
</html>
 

写法二:(和上面的写法1等价)

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script>
            function queryData() {
                return new Promise((resolve, reject) => {
                    setTimeout(function() {
                        var data = { retCode: 0, msg: 'qianguyihao' }; // 接口返回的数据
                        if (data.retCode == 0) {
                            // 接口请求成功时调用
                            resolve(data);
                        } else {
                            // 接口请求失败时调用
                            reject({ retCode: -1, msg: 'network error' });
                        }
                    }, 100);
                });
            }
 
            queryData()
                .then(
                    data => {
                        // 从 resolve 获取正常结果
                        console.log('接口请求成功时,走这里');
                        console.log(data);
                    },
                    data => {
                        // 从 reject 获取异常结果
                        console.log('接口请求失败时,走这里');
                        console.log(data);
                    }
                )
                .finally(() => {
                    console.log('无论接口请求成功与否,都会走这里');
                });
        </script>
    </body>
</html>
 

注意:写法1和写法2的作用是完全等价的。只不过,写法2是把 catch 里面的代码作为 then里面的第二个参数而已。

4、Promise 的常用API:对象方法【重要】

Promise 自带的API提供了如下对象方法:

  • Promise.all():并发处理多个异步任务,所有任务都执行成功,才能得到结果。
  • Promise.race(): 并发处理多个异步任务,只要有一个任务执行成功,就能得到结果。

下面来详细介绍:

Promise.all()代码举例:

代码举例:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script type="text/javascript">
            /*
              封装 Promise 接口调用
            */
            function queryData(url) {
                return new Promise((resolve, reject) => {
                    var xhr = new XMLHttpRequest();
                    xhr.onreadystatechange = function() {
                        if (xhr.readyState != 4) return;
                        if (xhr.readyState == 4 && xhr.status == 200) {
                            // 处理正常结果
                            resolve(xhr.responseText);
                        } else {
                            // 处理异常结果
                            reject('服务器错误');
                        }
                    };
                    xhr.open('get', url);
                    xhr.send(null);
                });
            }
 
            var promise1 = queryData('http://localhost:3000/a1');
            var promise2 = queryData('http://localhost:3000/a2');
            var promise3 = queryData('http://localhost:3000/a3');
 
            Promise.all([promise1, promise2, promise3]).then(result => {
                console.log(result);
            });
        </script>
    </body>
</html>

Promise.race()代码举例:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script type="text/javascript">
            /*
              封装 Promise 接口调用
            */
            function queryData(url) {
                return new Promise((resolve, reject) => {
                    var xhr = new XMLHttpRequest();
                    xhr.onreadystatechange = function() {
                        if (xhr.readyState != 4) return;
                        if (xhr.readyState == 4 && xhr.status == 200) {
                            // 处理正常结果
                            resolve(xhr.responseText);
                        } else {
                            // 处理异常结果
                            reject('服务器错误');
                        }
                    };
                    xhr.open('get', url);
                    xhr.send(null);
                });
            }
 
            var promise1 = queryData('http://localhost:3000/a1');
            var promise2 = queryData('http://localhost:3000/a2');
            var promise3 = queryData('http://localhost:3000/a3');
 
            Promise.race([promise1, promise2, promise3]).then(result => {
                console.log(result);
            });
        </script>
    </body>
</html>
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值