JavaScript学习之Promise

本文介绍了Promise作为异步编程解决方案的特点和用法,包括其三种状态转换、then、catch、all和race方法。通过实例解析了如何创建和使用Promise,特别讨论了Promise在处理多个并发请求时的行为。

一、引言

Promise是异步编程的解决方案之一,为了便于理解,我们可以把Promise想象成一个开了两个孔(一个代表“成功”,一个代表“失败”)的容器,容器里面存放着一个异步操作,当异步操作完成后,如果成功那么将数据从代表成功的孔中倒出,如果失败了,那么相关的错误信息将从失败的孔中倒出。

二、Promise的特点

Promise有两个特点

  1. Promise的状态有三种,Pending(进行中)、Fulfilled(成功)、Rejected(失败),且有两种状态转换过程,要么从Pending到Fulfilled,要么从Pending到Rejected。Promise的状态不会受外界的干扰
  2. Promise的状态一旦变为Fulfilled或Rejected后就不会再改变

三、Promise实例

    let promise = new Promise((resolve, reject) => {
        window.setTimeout(() => {
            resolve(1);
            //reject(1);
        }, 2000);
    });
    promise.then((data) => {
        console.info(`resolve:${data}`)
    }, (data) => {
        console.info(`reject:${data}`)
    });

代码中定义了一个Promise对象,包含了一个定时器任务,2s后 执行成功,返回数据1。这段代码执行后,2s后控制台将输出resolve:1。如果将reject(1)的注释去掉,将resolve(1)注释,那么控制台将输出reject:1。

Promise的构造函数接收两个参数resolve和reject(参数名随意),它们的含义为:当异步操作成功了,要调用resolve,当异步操作失败了,要调用reject,无论是resolve还是reject我们都可以传递一些数据,然后在then方法中我们可以获得这个数据。then方法也接收两个函数作为参数,第一个是Promise的状态变成Fullfilled时的回调函数,第二个是Promise的状态变成Rejected时的回调函数。接下来,让我们一起学习一下Promise的属性和方法。

四、Promise的属性和方法

  • Promise.prototype.Promise

Promise的构造函数接收一个函数对象,这个函数对象拥有两个参数resolve和reject(本质上是浏览器提供的特殊函数,我们暂且称之为状态转换函数),resolve的作用是将Promise的状态从Pending变成Fulfilled,reject的作用是将Promise的状态从Pending变成Rejected,我们在函数对象体内的异步操作完成后可以根据异步操作的结果调用响应的状态转换函数即可修改Promise的状态。

    new Promise((resolve, reject) => {
        if (异步操作成功) {
            resolve(数据);
        } else {
            reject(失败信息);
        }
    });

 

  • Promise.prototype.then

then方法用来为Promise添加状态转换时的回调函数,then的第一个参数时Resolved状态时的回调(接收resolve()方法传递的数据),第二个参数时Rejected状态的回调(接收reject()方法传递的失败信息),then方法将返回一个新的Promise实例。

    new Promise((resolve, reject) => {
        if (异步操作成功) {
            resolve(数据);
        } else {
            reject(失败信息);
        }
    }).then((数据)=>{
        
        },(失败信息)=>{
        
        });

 

  • Promise.prototype.catch

catch方法可以看做是then(null,()=>{})的别名,用于在Promise状态变为Rejected时或者代码中出现未捕获的错误时,执行相应的逻辑,一般的用法如下,

    new Promise((resolve, reject) => {
        if (异步操作成功) {
            resolve(数据);
        } else {
            reject(失败信息);
        }
    }).then((数据)=>{
        
        }).catch((失败信息或者发生的错误)=>{
        
        });
  • Promise.prototype.all

all方法接收一个Promise数组作为参数,将这些Promise组合成一个新的Promise返回,当且仅当数组中所有子Promise的状态都变成Fulfilled时,新Promise得状态才会变成Fulfilled,且每一个子Promise传递的数据会存放在一个数组中作为then的回调参数。一旦某个子Promise状态变为Rejected那么新Promise的状态就会变成Rejected,且这个子Promise的错误信息会传递给catch。

// 定义生成Promise的方法
function newPromise(msg, timeout) {
        let promise = new Promise((resolve, reject) => {
            console.log(`Promise ${msg} 开始运行`);
            window.setTimeout(() => {
                console.log(`Promise ${msg} 运行完毕`);
                resolve(msg);
            }, timeout);
        });
        return promise;
    }

// 生成三个执行时间不同的Promise交给all,只有运行时间最长的p3执行完毕后。新Promise的状态的才会变成Fulfilled,输出 Promise.all p1,p2,p3

    Promise.all([newPromise("p1", 1000), newPromise("p2", 2000), newPromise("p3", 3000)]).then(rsp => {
        console.info(`Promise.all ${rsp}`);
    }).catch(e=>{
        console.info(`error ${e}`);
    });

//3s后输出Promise.all p1,p2,p3
  • Promise.prototype.race

race方法同样接收一个Promise数组作为参数,和all方法不同的是,当有一个子Promise的状态变换时,新Promise的状态就会跟着这个子Promise变换。

// 定义生成Promise的方法
function newPromise(msg, timeout) {
        let promise = new Promise((resolve, reject) => {
            console.log(`Promise ${msg} 开始运行`);
            window.setTimeout(() => {
                console.log(`Promise ${msg} 运行完毕`);
                resolve(msg);
            }, timeout);
        });
        return promise;
    }

// 生成三个执行时间不同的Promise交给race,运行时间短的p1第一个执行完毕后,新Promise的状态的变成Fulfilled,输出 Promise.race p1

    Promise.race([newPromise("p1", 1000), newPromise("p2", 2000), newPromise("p3", 3000)]).then(rsp => {
        console.info(`Promise.race ${rsp}`);
    }).catch(e=>{
        console.info(`error ${e}`);
    });

//1s后输出Promise.race p1
  • API持续补充中......

五、Promise实例

下面给出一个使用Promise封装ajax的例子,来加深对Promise的理解

/**
     * 使用Promise封装ajax
     * @param url 请求地址
     * @param type 请求类型
     * @returns {Promise<unknown>}
     */
    let myAjax = function (url, type) {
        let promise = new Promise((resolve, reject) => {
                let ajax = new XMLHttpRequest();
                ajax.open(type, url);
                ajax.onreadystatechange = () => {
                    if (ajax.readyState !== 4) {
                        return;
                    }
                    if (ajax.status === 200) {
                        resolve(ajax.responseText);
                    } else {
                        reject(ajax.status);
                    }
                }
                ajax.send();
            })
        ;
        return promise;
    }
    // data.json是同目录的一个json数据文件,用来模拟服务器返回的数据
    myAjax("data.json", "get").then((rsp) => {
        console.info(JSON.parse(rsp))
    }, (err) => {
        console.info(err);
    });

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值