ES6的promise

Promise是什么

1、Promise是js中的一个原生对象,是一种异步编程的解决方案。可以替换掉传统的回调函数解决方案,将异步操作以同步的流程表达出来。

2、Promise有三种状态:pending(初始化)、fulfilled(成功)、rejected(失败)

可以通过resolve()与reject()改变当前的promise对象的状态

● resolve()使当前promise对象状态改为fulfilled

● reject()使当前promise对象状态改为rejected

● 一般抛出异常也会导致promise对象状态改为rejected

3、相关概念

回调函数:当一个函数作为参数传入另一个函数中,当满足一定条件后该函数才执行,这种函数就称为回调函数。例如我们熟悉的定时器就存在回调函数。

同步任务:同步任务在主线程上排队执行,只有前一个任务执行完毕,才能执行下一个任务。

异步任务:异步任务不进入主线程,而是进入异步队列,前一个任务是否执行完毕不影响下一个任务的执行。

为什么使用Promise

Promise对象提供了简洁的API,使得控制异步操作更加容易。可以很好地解决回调地狱问题

1、回调地狱

为了在异步函数当中顺序执行代码而而不断嵌套调用回调函数,例如以下代码:

javascript 复制代码
setTimeout(() => {
    console.log('setTimeout1');
    setTimeout(() => {
        console.log('setTimeout2');
        setTimeout(() => {
            console.log('setTimeout3');
        }, 1000);
    }, 2000);
}, 3000);// 分别输出setTimeout1、setTimeout2、setTimeout3

2、Promise链式编程解决回调地狱

javascript 复制代码
getPromise(str, time) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(str)
        }, time);
    });
}
const p1 = this.getPromise('setTimeout1', 3000);
const p2 = this.getPromise('setTimeout2', 2000);
const p3 = this.getPromise('setTimeout3', 1000);
p1.then((data1) => {
    console.log(data1);
    return p2;
})
.then((data2) => {
    console.log(data2);
    return p3;
})
.then((data3) => {
    console.log(data3);
})// 依次输出setTimeout1、setTimeout2、setTimeout3

基本用法

1、 new实例化一个promise对象,构造函数中接收一个函数作为参数,该函数支持传入2个参数resolve和reject。

2、将需要处理的异步任务写在该函数内,异步任务执行成功时调用resolve返回结果,执行失败时调用reject回调函数。

3、通过promise.then接收处理成功时响应的数据,catch接收处理失败时响应的数据。

javascript 复制代码
const promise1 = new Promise((resolve, reject) => {
    axios.get("/api/mock-data/list/v1").then((e) => {
        if (e.data.status == 200) {
            resolve(e.data);
        } else {
            reject({errCode: -1});
        }
    });
});
promise1.then((data) => {
    console.log('接口返回数据===',data);
})
.catch((err) => {
    console.log('接口响应错误===',err);
});
// 模拟接口数据1:通过then()获取
{
    status: 200,
    message: 'success',
    data: [{
        id: 1,
        name: 'xiaoming',
        age: '21',
        job: '前端工程师'
    }, {
        id: 2,
        name: 'xiaozhang',
        age: '28',
        job: '后端工程师'
    }]
}
// 模拟接口数据2:通过catch()捕获
{
  status: 404,
  message: 'Not Found',
  data: null
}

常用API

promise.then():获取异步任务的成功结果,支持2个函数参数(成功和失败回调),一般来说then中只处理成功的

promise.catch():获取异步任务的失败结果,和then函数参数中失败回调作用一样,处理错误,由于Promise抛出错误具有冒泡性质,能够不断传递,会传到catch中,所以一般来说所有错误处理放在catch中,then中只处理成功的,同时catch还会捕捉resolved中抛出的异常(代码报错)

promise.finally():异步任务成功与否,都会执行

Promise.all():Promise.all([promise1,promise2])------参数是对象数组。以慢为准,等数组中所有的promise对象状态为resolved时,该对象就为resolved;只要数组中有任意一个promise对象状态为rejected,该对象就为rejected

javascript 复制代码
const p1 = new Promise((resolve, reject) => {
    resolve({ errCode: 0 });
});
const p2 = new Promise((resolve, reject) => {
    resolve({ errCode: -1 });
});
const p3 = new Promise((resolve, reject) => {
    resolve({ errCode: -2 });
});
const promises = Promise.all([p1, p2, p3]);
promises
.then((data) => {
    console.log("Promise.all.then===", data);
})
.catch((err) => {
    console.log("Promise.all.catch===", err);
});
// 运行结果为:Promise.all.then===
//[
//    {
//        "errCode": 0
//    },
//    {
//        "errCode": -1
//    },
//    {
//        "errCode": -2
//    }
//]
const p1 = new Promise((resolve, reject) => {
    resolve({ errCode: 0 });
});
const p2 = new Promise((resolve, reject) => {
    reject({ errCode: -1 });
});
const p3 = new Promise((resolve, reject) => {
    reject({ errCode: -2 });
});
const promises = Promise.all([p1, p2, p3]);
// const promises = Promise.race([p2, p1, p3]);
promises
.then((data) => {
    console.log("Promise.all.then===", data);
})
.catch((err) => {
    console.log("Promise.all.catch===", err);
});
// 运行结果为:Promise.all.catch===
//{
//   "errCode": -1
//}

Promise.race():Promise.race([promise1,promise2])------参数是对象数组。以快为准,数组中所有的promise对象,有一个先执行了何种状态,该对象就为何种状态,并执行相应函数

javascript 复制代码
const p1 = new Promise((resolve, reject) => {
    reject({ errCode: 0 });
});
const p2 = new Promise((resolve, reject) => {
    resolve({ errCode: -1 });
});
const p3 = new Promise((resolve, reject) => {
    resolve({ errCode: -2 });
});
const promises = Promise.race([p2, p1, p3]);
promises
.then((data) => {
    console.log("Promise.all.then===", data);
})
.catch((err) => {
    console.log("Promise.all.catch===", err);
});
// 运行结果为:Promise.all.then===
//{
//    "errCode": -1
//}

Promise缺点

代码冗余,异步任务通过new Promise包装后,都需要使用then调用,导致一眼看出都是then..then..then,不利于代码维护。

async/await

async/await 是ES7提出的基于Promise的解决异步的最终方案。

async:是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值。因此对async函数可以直接then,返回值就是then方法传入的函数。

javascript 复制代码
async fn() {
    return 123456;
},
this.fn().then((data) => {
    console.log('async===',data);
})
// 输出为:async=== 123456
// 注意:未加async修饰的函数,是不能直接.then的

await: 也是一个修饰符,只能放在async定义的函数内。可以理解为等待

await 修饰Promise对象:可以获取Promise中返回的内容(resolve或reject的参数),且取到值后语句才会往下执行;

示例:

javascript 复制代码
async fn() {
    let data = '';
    axios.get("/api/mock-data/list/v1").then((e) => {
        data = e.data;
    });
    console.log('data===',data);// 输出data值为''
}

await修饰后:new Promise可以省略

javascript 复制代码
async fn() {
    let data = '';
    data = await new Promise((resolve, reject) => {
        axios.get("/api/mock-data/list/v1").then((e) => {
            resolve(e.data);
        });
    });
    console.log('data===',data);// 输出data为接口返回值
}

总结:await实际会暂停函数的执行,直到promise状态变为完成,然后继续执行。

javascript 复制代码
async fn() {
    console.log('123');
    let data1 = await new Promise((resolve, reject) => {
        axios.get("/api/mock-data/list/v1").then((e) => {
            resolve(e.data);
        });
    });
    let data2 = await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('success');
        }, 3000);
    });
    console.log('456');
    console.log('data1===',data1);
    console.log('data2===',data2);
},
this.fn();//立即输出123,3秒后分别输出456、data1、data2

tips

当浏览器出现报错Uncaught (in promise) err时,检查是否有reject错误未捕获,增加catch分支即可。

相关推荐
brrdg_sefg10 分钟前
Rust 在前端基建中的使用
前端·rust·状态模式
m0_7482309435 分钟前
Rust赋能前端: 纯血前端将 Table 导出 Excel
前端·rust·excel
qq_5895681043 分钟前
Echarts的高级使用,动画,交互api
前端·javascript·echarts
黑客老陈2 小时前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安2 小时前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite
暴富的Tdy2 小时前
【CryptoJS库AES加密】
前端·javascript·vue.js
neeef_se2 小时前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel
m0_748235612 小时前
web 渗透学习指南——初学者防入狱篇
前端