【学习笔记72】 Promise和async 与 await
2023-09-11 14:14:57 时间
一、Promise
- 一个新的异步代码封装方案
- 以前通过回调函数的形式去封装, 会导致出现回调地狱
- 现在换promise 后, 就解决了这个问题
1、promise 它会有三个状态
- 持续: pending
- 成功: fulfilled
- 失败: rejected
2、promise 只会发生两个转换
- 持续 ==> 成功
- 持续 ==> 失败
3、promise实例化对象的方法
- .then
- .catch
4、代码的实现
const p = new Promise(function (resolve, reject) {
/**
* resolve 会把我们这个 promise 状态转换为 成功
* reject 会把我们这个 promise 状态转换为 失败
*
* 这两个 都是 函数
*/
console.log('班长帮我去买一瓶水')
const timer = Math.ceil(Math.random() * 3000) + 2000
setTimeout(() => {
if (timer > 3500) {
console.log('班长买水失败', timer)
reject('班长买水失败, 再换个地方买')
} else {
console.log('班长买水成功', timer)
resolve('班长买水成功, 奖励二十个bug')
}
}, timer)
})
p.then(function (res) {
// promise 成功状态时触发
//并且接受resolve时传递的参数
console.log(res);
})
p.catch(function (res) {
// promise失败状态时触发
// 并且接受reject时传递的参数
console.log(res);
})
5、promise实例化对象可以接受链式调用
const p = new Promise(function (resolve, reject) {
console.log('班长帮我去买一瓶水')
const timer = Math.ceil(Math.random() * 3000) + 2000
setTimeout(() => {
if (timer > 3500) {
console.log('班长买水失败', timer)
reject('班长买水失败, 再换个地方买')
} else {
console.log('班长买水成功', timer)
resolve('班长买水成功, 奖励二十个bug')
}
}, timer)
})
p.then(function (res) {
console.log(res)
}).catch(function (res) {
console.log(res)
})
二、封装promise
- promise.then内部return了一个新的 promise对象
- 可以在后续再写几个 .then
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000) + 2000
setTimeout(() => {
if (timer > 3500) {
reject('班长买水失败, 再换个地方买')
} else {
resolve('班长买水成功, 奖励二十个bug')
}
}, timer)
})
return p
}
fn().then((res) => {
console.log('班长第一次买水成功')
return fn()
}).then((res) => {
console.log('班长第二次买水成功')
return fn()
}).then((res) => {
console.log('班长第三次买水成功')
}).catch((res) => {
console.log('班长买水失败')
})
三、async 与 await
- 作用: 能帮助我们把异步代码, 写的和同步代码一样
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000)
setTimeout(() => {
if (timer > 3500) {
reject('班长真好, 就是买水失败, 再换个地方买')
} else {
resolve('班长真好, 就是买水成功, 奖励二十个bug')
}
}, timer)
})
return p
}
// 1. 函数开头必须书写async表明内部可以书写await
async function newFn() {
/**
* await 后边需要跟着promise
* await表示等到的意思, 执行到fn(),虽然是异步的
* 但是因为有await关键字, 此时不会往下继续执行,
* 而是等待 fn()执行完毕, 在往下执行
*/
let r1 = await fn()
console.log(r1)
// console.log('如果失败了, 执行这行代码, 提示用户网络有问题')
}
newFn()
四、async与await的问题
- 没有办法捕获到错误, 只能接受promise的成功状态
- 如果报错, 会中断程序执行
解决方法1: try...catch
- 首次执行的时候,会走try这个分支, 如果这个位置有报错
- 他会结束执行try分支, 然后走catch分支
- 如果再运行try分支的时候, 没有报错, 那么catch不会运行
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000) + 2000
setTimeout(() => {
if (timer > 3500) {
reject('班长真好, 就是买水失败, 再换个地方买')
} else {
resolve('班长真好, 就是买水成功, 奖励二十个bug')
}
}, timer)
})
return p
}
async function newFn() {
try {
let r1 = await fn()
console.log(r1)
} catch (error) {
console.log(error)
}
}
newFn()
解决方法2: 更改 promise 的封装
- 原因: promise执行reject时,async await不能捕获到错误,
- 解决: 让这个promise不管什么情况都返回resolve,我们通过返回的参数, 区分现在时成功还是失败
- 开发中,对象内的code如果为0, 一般代表失败;对象内的code如果为1, 一般代表成功
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000) + 1000
setTimeout(() => {
if (timer > 3500) {
// reject('班长真好, 就是买水失败, 再换个地方买')
resolve({
code: 0,
msg: '班长真好, 就是买水失败, 再换个地方买'
})
} else {
resolve({
code: 1,
msg: '班长真好, 就是买水成功, 奖励二十个bug'
})
}
}, timer)
})
return p
}
async function newFn() {
let r1 = await fn()
if (r1.code === 0) {
console.log('您的网络有问题')
} else {
console.log(r1.msg)
}
}
newFn()
五、promise的其他方法
(一)finally
- promise 实例化对象还有一个方法(finally)
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000) + 2000
setTimeout(() => {
if (timer > 3500) {
reject('失败')
} else {
resolve('成功')
}
}, timer)
})
return p
}
fn().then(res => {
console.log('成功了: ', res)
}).catch(res => {
console.log('失败了: ', res)
}).finally(res => {
console.log('不管成功还是失败,都会执行')
})
(二)Promise构造函数上也有一些方法
1、all
- all接受一个数组, 数组内可以传递多个promise对象
- all方法的状态取决数组内部的promise对象的状态
- 如果都是成功, all方法也是成功
- 如果有一个失败, all方法就是失败
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000) + 2000
setTimeout(() => {
if (timer > 3500) {
reject('失败')
} else {
resolve('成功')
}
}, timer)
})
return p
}
Promise.all([fn(), fn(), fn()])
.then(res => {
console.log('如果我输出, 代表所有promise对象都是成功状态')
})
.catch(res => {
console.log('如果我输出, 代表最少有一个promise状态为失败状态')
})
2、race
- race接受一个数组, 数组内可以传递多个 promise 对象
- race 方法的状态取决于,数组内部的 promise 对象中第一个结束的
- 如果第一个结束时是成功, race 就是成功
- 如果第一个结束时时失败, race 就是失败
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000) + 2000
setTimeout(() => {
if (timer > 3500) {
reject('失败')
} else {
resolve('成功')
}
}, timer)
})
return p
}
Promise.race([fn(), fn(), fn()])
.then(res => {
console.log('如果我执行, 代表数组内第一个结束的promise状态为成功')
})
.catch(res => {
console.log('如果我执行, 代表数组内第一个结束的promise状态为失败')
})
3、allSettled
- allSettled 接受一个数组, 数组内可以传递多个 promise
- 他只会执行 .then, 接收到的参数是一个数组形式的, 内部元素为对应的promise的状态
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000) + 2000
setTimeout(() => {
if (timer > 3500) {
reject('失败')
} else {
resolve('成功')
}
}, timer)
})
return p
}
Promise.allSettled([fn(), fn(), fn(), fn()])
.then(res => {
console.log(res)
})
4、强行帮我们返回一个成功状态的 promise 对象
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000) + 2000
setTimeout(() => {
if (timer > 3500) {
reject('失败')
} else {
resolve('成功')
}
}, timer)
})
return p
}
Promise.resolve()
.then(res => {
console.log('成功')
}).catch(res => {
console.log('失败')
})
5、强行帮我们返回一个失败状态的promise 对象
function fn() {
const p = new Promise(function (resolve, reject) {
const timer = Math.ceil(Math.random() * 3000) + 2000
setTimeout(() => {
if (timer > 3500) {
reject('失败')
} else {
resolve('成功')
}
}, timer)
})
return p
}
Promise.reject()
.then(res => {
console.log('成功')
}).catch(res => {
console.log('失败')
})
相关文章
- spring学习笔记(22)声明式事务配置,readOnly无效写无异常
- Coursera台大机器学习技法课程笔记14-Radial Basis Function Network
- Coursera台大机器学习技法课程笔记07-Blending and Bagging
- Struts2学习笔记《三》
- java笔记十一:动态编译
- Django学习笔记之——Start
- Linq学习笔记(转)
- 云笔记应用推荐
- CCNA2.0笔记_TCP/IP概述
- RestfulApi 学习笔记——查询与过滤还有搜索(五)
- backbone学习笔记:集合(Collection)
- Opencv学习笔记 - 基于图的分割
- Android开发学习笔记(十)屏幕适配
- Cypress 启动本地浏览器的学习笔记
- Angular 服务器端渲染的学习笔记(二)
- 数据结构学习笔记之基础概念(01)
- mongodb 学习笔记05 --用户管理
- Android原生(Native)C开发之四:SDL移植笔记
- Java中Connection方法笔记
- 腾讯云大学电影周周看课程学习笔记
- 视觉SLAM笔记三之视觉SLAM框架解读
- GAN全套学习笔记/论文