1. 基本概念
1) 作用: 一种新的异步代码封装方案, 用来代替 回调函数的
3种状态?
1. 持续 pending
2. 成功 fullfilled (resolved)
3. 失败 rejected
+ 注意: 一个Promise的状态转换只有两种
1. 持续 => 成功
2. 持续 => 失败
3) Promise 基本语法
promise 是 JS 内置的一个构造函数 ,书写固定格式记住即可
1. 创建promise
语法: let p = new Promise(function(第一个形参,第二个形参){异步代码})
- resolve 第一个形参: 内部的值是一个函数, 调用之后可以将当前这个 promise 的状态设置为 成功
resolve(a)运行后,其实调用的是then(b=>{ })里的箭头函数b=>{ }, 箭头函数里形参数b其实就是resolve的实参a
- reject 第二个形参: 内部的值是一个函数, 调用之后可以将当前这个 promise 的状态设置为 失败
5) 状态转换时,触发的函数
=> then 方法: resolve()会将 promise 状态成功。然后运行then里面的代码
=> catch 方法: reject() 会将 promise 状态失败。状态转为失败, 触发catch函数,并执行里面的函数
- 如果Promise对象状态为 成功 就运行then里的函数。
- 如果Promise对象状态为 失败 就运行catch里的函数
promise 中的代码执行出现异常,则默认promise状态转为失败,而且代码不会抛出异常中断,而是将异常信息,传递给catch(形参)函数 的形参
promise中的代码都是同步执行,但是then,catch注册的函数是异步执行, then\catch方法要等到 Promise对象改变状态后再执行
<script>
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000)
console.log('班长, 去帮我买瓶水')
setTimeout(() => {
if (timer > 1500) {
console.log('买水失败, 用时: ', timer)
reject()
} else {
console.log('买水成功, 用时: ', timer)
resolve()
}
}, timer)
})
console.log('打印 变量 p: ', p)
p.then(() => {
console.log('如果我这行内容打印, 说明 promise 的状态为 成功')
})
p.catch(() => {
console.log('如果我这行内容打印, 说明 promise 的状态为 失败')
})
</script>
2. 将 promise 封装到函数中(了解即可)
第1版 多次调用封装了promise的函数
缺点:无法确定是哪一次失败
<script>
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000)
console.log('班长, 去帮我买瓶水')
setTimeout(() => {
if (timer > 1500) {
reject('超时, 所以买水失败')
} else {
resolve('没有超时, 买水成功')
}
}, timer)
})
return p
}
const res = fn()
res.then((str) => {
中箭头函数的形参str
console.log(`因为 ${str}, 所以奖励班长 10 个 bug`)
return fn()
}).then((str) => {
console.log('如果我输出了, 表示班长 第二次买水成功')
return fn()
}).then((str) => {
console.log('如果我输出了, 表示班长 第三次买水成功')
}).catch((str) => {
console.log(`如果我输出了, 说明之前某一次买水失败了`)
})
</script>
3. async 与 await
async 与 await能够将 异步代码, 写的像 "同步代码一样"
async: 书写在 一个函数的 开头, 表明当前函数是一个异步函数, 内部可以书写 await
await: 具有等待的含义, 书写在 fn函数 前, 代码运行到这个位置的时候, 会有一个等待效果
一直等到这个fn函数中的异步任务结束, 并且将异步任务的反馈结果 当一个值返回出来
<script>
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000)
console.log('班长, 去帮我买瓶水')
setTimeout(() => {
if (timer > 1000) {
reject('超时, 所以买水失败')
} else {
resolve('没有超时, 买水成功')
console.log('第xx次买水: ', rx)
}
}, timer)
})
return p
}
newFn()
async function newFn() {
const r1 = await fn()
console.log('第一次买水: ', r1)
const r2 = await fn()
console.log('第二次买水: ', r2)
const r3 = await fn()
console.log('第三次买水: ', r3)
}
</script>
1. async 与 await 的缺点
不能正常的捕获到 promise 的失败状态
1)用try...catch方法 解决缺点
<script>
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000)
console.log('班长, 去帮我买瓶水')
setTimeout(() => {
if (timer > 1000) {
reject('超时, 所以买水失败')
} else {
resolve('没有超时, 买水成功')
}
}, timer)
})
return p
}
newFn()
async function newFn() {
try {
const r1 = await fn()
console.log('第一次买水: ', r1)
} catch (error) {
console.log(error)
}
console.log('上层有try-catch,即使上层error报错,也可以继续向下执行,不会中断')
try {
const r1 = await fn()
console.log('第二次买水: ', r1)
} catch (error) {
console.log(error)
}
}
</script>
2)封装一个永远不会失败的 promise 解决缺点
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000)
console.log('班长, 去帮我买瓶水')
setTimeout(() => {
if (timer > 1500) {
resolve({
code: 0,
msg: '超时, 所以买水失败'
})
} else {
resolve({
code: 1,
msg: '没有超时, 买水成功'
})
}
}, timer)
})
return p
}
newFn()
async function newFn() {
const r1 = await fn()
if (r1.code === 0) {
console.log('请求失败的补救措施')
} else {
console.log('请求成功, 正常执行代码即可')
}
}
4. promise 的其他方法
1. promise 对象上的方法: then-catch-finally
正常业务场景中, 我们再发起一个请求的时候, 会将页面弹出一个遮罩层
然后再请求结束的时候 需要将这个遮罩层关闭
这个时候如果放在 then 中 那么会有一个 问题, 就是请求失败的时候不会触发then
所以我们一般不会放在 then 关闭遮罩层, 而是 放在 finally 中
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000)
console.log('班长, 去帮我买瓶水')
setTimeout(() => {
if (timer > 1500) {
reject('超时, 所以买水失败')
} else {
resolve('没有超时, 买水成功')
}
}, timer)
})
return p
}
const res = fn()
res.then(() => {
console.log('成功时执行')
}).catch(() => {
console.log('失败时执行')
}).finally(() => {
console.log('每一次都会执行 (不会考虑成功还是失败)')
})
2. promise 构造函数上的一些方法
Promise.all
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000)
console.log('班长, 去帮我买瓶水')
setTimeout(() => {
if (timer > 1500) {
reject('超时, 所以买水失败')
} else {
resolve('没有超时, 买水成功')
}
}, timer)
})
return p
}
Promise.all([fn(), fn(), fn()]).then(() => {
console.log('所有的 参数 全部都返回一个 成功状态的时候, 会执行')
}).catch(() => {
console.log('所有参数中, 有一个为失败状态, 就会执行 catch')
})
Promise.race
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000)
console.log('班长, 去帮我买瓶水')
setTimeout(() => {
if (timer > 1500) {
reject('超时, 所以买水失败')
} else {
resolve('没有超时, 买水成功')
}
}, timer)
})
return p
}
Promise.race([fn(), fn(), fn()]).then(() => {
console.log('这些参数中, 结束最快的那一个状态为 成功的时候执行')
}).catch(() => {
console.log('这些参数中, 结束最快的那一个状态为 失败的时候执行')
})
Promise.allSettled
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000)
console.log('班长, 去帮我买瓶水')
setTimeout(() => {
if (timer > 1500) {
reject('超时, 所以买水失败')
} else {
resolve('没有超时, 买水成功')
}
}, timer)
})
return p
}
Promise.allSettled([fn(), fn(), fn()]).then((res) => {
console.log(res)
})

Promise.resolve
Promise.resolve().then(() => {
console.log('强制返回一个 状态为 成功的 promise')
})
Promise.reject
Promise.reject().then(() => {
console.log('如果我打印了, 说明 当前的 promise 状态为成功')
}).catch(() => {
console.log('强制返回一个 状态为 失败的 promise 对象')
})