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分支即可。

相关推荐
Qrun29 分钟前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp30 分钟前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.1 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl3 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫5 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友5 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理7 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻7 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
mapbar_front8 小时前
在职场生存中如何做个不好惹的人
前端
牧杉-惊蛰8 小时前
纯flex布局来写瀑布流
前端·javascript·css