什么是Promise?
首先,Promise是ES6新增的一种对象,中文可以叫做期约。他的出现是为了简化异步编程。那么什么是异步编程?
什么是异步编程?
异步编程是一种编程的方式。
简单来说,当代码的运行过程种出现了一个耗时的操作(如文件读写、网络请求、数据库查询等)的时候,该耗时操作不会使得后续的代码被它所影响,而是继续运行。
举个🌰
比如你的需求是做如下几件事情:
- 双击桌面的
云原神图标 - 排队等待进入游戏(耗时操作,除非你是氪金用户不用排队🤑)
- 刷朋友圈
如果是非异步的代码,那么当你做完第一步之后、你就只能傻愣愣地排队等待进入游戏了,你啥也不能做,只能等着。
然后任务2完成之后,你进入了游戏,你才开始刷朋友圈。
但是如果是异步的代码,你就可以在排队等待进入游戏的过程中,利用这个等待的时机去刷一刷朋友圈了,而不是在干等着啥也不干。
所以其实异步的思维才符合我们的直觉。
没有Promise的异步操作麻烦在哪里?为啥就需要Promise来简化?
😎回顾一下:我们说Promise的出现简化了异步操作,而异步操作就是当我遇到一个耗时的操作的时候,我可以先不管他,先执行这个耗时操作后面的操作。
那肯定是原来的异步操作有亿些不太方便的地方了,才来了一个Promise来简化的。
我就没听过谁说过0~5以内的加减法需要简化的。
那么下面就来简单说下没有Promise的异步操作麻烦在哪里?为啥就需要Promise来简化?
这方面不是重点(重点是后面的Promise),简要的说,有下面几个麻烦的地方:
- ☹️回调地狱(Callback Hell)😭
一个异步操作依赖于另一个异步操作的结果时,我们可能会遇到嵌套的回调函数,这会让代码变得难以阅读和维护
- ☹️错误处理困难😭
回调函数嵌套过多时,错误传播和处理会变得非常困难。
- ☹️无法链式调用😭
没有
.then()方法,man!这谁受得了。
言而总之+总而言之,Promise来了
下面,Promise
启动✨!就是为什么Promise(以及后来的async/await)在JavaScript中变得如此重要的原因。
下面就是Promise的使用了✨✨✨✨✨巨重要
P.S. 如果大家是新手的话,推荐大家在谷歌浏览器的控制台多手敲几遍,很快就熟悉了😎
P.S. 再Promise中,存在三种状态:
- 异步操作未完成【pending】【adj. 未决定的】
- 异步操作成功【fulfilled】【adj. 满足的】
- 异步操作失败【rejected】【adj. 被拒的】 其中,
fulfilled与rejected两种状态都是resolved【adj. 已解决的】。大家只要记住,状态的改变只会从
pending到fulfilled,或者从pending到rejected没有其他的状态改变方式了
这个搞懂,就可以看下面的Promise的简单例子了
例子 1:创建和使用一个简单的Promise
代码:
const myFirstPromise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve('成功😎');
} else {
reject('失败😭');
}
});
myFirstPromise
.then(result => {
console.log(result); // 输出: 成功😎
})
.catch(error => {
console.error(error);
});
解析:
new Promise创建一个Promise对象,接受一个函数作为参数,该函数包含两个参数:resolve和reject。resolve和reject分别用于表示操作的成功和失败。- 在示例中,我们用一个布尔值
success来决定调用resolve还是reject。 then方法注册了一个回调函数,这个回调函数会在Promise被成功解析时执行,并接收解析值。catch方法注册了一个回调函数,这个回调函数会在Promise被拒绝时执行,并接收错误信息。
例子 2:链式调用(Chaining Promises)
代码:
const step1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('原'), 1000);
});
step1
.then(result => {
console.log(result);
// 返回一个新的Promise
return new Promise((resolve, reject) => {
setTimeout(() => resolve('神'), 1000);
});
})
.then(result => {
console.log(result);
// 返回一个新的Promise
return new Promise((resolve, reject) => {
setTimeout(() => resolve('启动!'), 1000);
});
})
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
});
解析: 乍一看很长,其实真挺长的。 但是其实一点都不难,纸老虎(paper tiger)而已。
step1是一个Promise对象,在1秒钟后解析。- 使用
then方法处理step1的结果,并返回一个新的Promise。 - 这个新的Promise在1秒钟后解析,并使用另一个
then方法处理其结果。 - 这种链式调用允许我们将多个异步操作按顺序连接起来,每个操作在前一个操作完成后开始。
例子 3:并行Promise(Promise.all)
代码:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('原'), 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('神'), 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('启动!'), 3000);
});
Promise.all([promise1, promise2, promise3])
.then(results => {
console.log(results); // 输出: [原', '神', '启动!']
})
.catch(error => {
console.error(error);
});
解析:
promise1,promise2,promise3是三个独立的Promise对象,分别在1秒、2秒和3秒后解析。Promise.all方法接收一个Promise数组,当所有Promise都被解析时,返回一个新的Promise,这个新的Promise解析后的值是一个包含所有输入Promise解析值的数组。- 如果其中任何一个Promise被拒绝,
Promise.all返回的Promise也会立即被拒绝,并且拒绝原因是第一个被拒绝的Promise的拒绝原因。
例子 4:Promise.race
代码:
const promiseA = new Promise((resolve, reject) => {
setTimeout(() => resolve('我最快'), 1000);
});
const promiseB = new Promise((resolve, reject) => {
setTimeout(() => resolve('我第二快'), 2000);
});
const promiseC = new Promise((resolve, reject) => {
setTimeout(() => resolve('我最慢'), 3000);
});
// 注意,将多个Promise对象放入数组中
Promise.race([promiseA, promiseB, promiseC])
.then(result => {
console.log(result); // 输出: 我最快
})
.catch(error => {
console.error(error);
});
解析:
promiseA,promiseB,promiseC是三个独立的Promise对象,分别在1秒、2秒和3秒后解析。Promise.race方法接收一个Promise数组,当第一个Promise被解析或拒绝时,返回一个新的Promise,这个新的Promise解析值是第一个解析或拒绝的Promise的值。- 在这个例子中,由于
promiseA最先解析,因此Promise.race返回的Promise也会解析,值为promiseA的解析值。
最后
本文是对Promise的简单使用。 后续更文计划: 我后续会先写生成器和迭代器的内容,然后再写async和await的内容。