回调函数、回调地狱,异常函数 Promise / then 和 catch / async 与 await / try...catch 的应用
回调函数
把 函数1 通参数的形式传递给 函数2, 在函数2内部以形参方式调用,函数1就叫 函数2的回调函数 通常用到回调函数的场景都是在异步代码封装
-
简单的回调函数
把 函数A 通参数的形式传递给 函数B, 在函数B内部以形参方式调用,函数A就叫 函数B的回调函数
function A () {
console.log('函数A执行')
}
function B(cb) {
console.log('函数B执行')
cb()
}
B(A); // A 函数作为实参 传入 b函数中 => 先执行B函数 通过B函数内部调用A函数
- 封装 异步函数 1 => 一般都是网络请求
function fun(f){
const time = Math.ceil(Math.random()*3000);
/*
随机数 返回值作为倒计时器 时间 当时间到达0时 执行当前函数 当前函数执行完毕后 调用函数fu()
fu()再执行
*/
setTimeout(() => {
console.log('异步函数执行',time);
f();
},time)
}
fun(
function fu(){ // 函数 fu() 在此时为实参 传入函数 fun() 中,在 fun() 内部调用
console.log('异步函数执行完后再执行');
}
)
-
封装 异步函数 2
封装一个形如网络请求的异步函数 , 通过随机数生成时间来判断来判断是否请求成功, 当请求大于某一时间,请求失败,反之则请求成功
function fun(sb,cg){
const time = Math.ceil(Math.random()*3000); // 随机数 返回值作为倒计时器 时间
setTimeout(() => {
// 当时间大于3500 时 判断请求失败
if(time > 3500){
console.log('请求失败');
// 请求失败后调用sb函数
sb();
}else{
console.log('请求成功');
// 请求成功 调用cg函数
cg();
}
},time);
}
fun(
// 参数1
() => {
console.log('请求失败,不能继续访问');
},
// 参数2
() => {
console.log('请求成功,可以继续访问');
}
)
回调地狱
回调地狱并非一个 bug,而是一种代码格式,而这种代码格式不利于我们阅读
需求:在网络请求时,发出判断,如果时间大于请求时间,请求失败,不再请求,如果未超过请求时间,则请求成功,继续请求
function fun(sb, cg) {
const time = Math.ceil(Math.random() * 3000) + 2000; // 随机数 返回值作为倒计时器 时间
setTimeout(() => {
// 当时间大于3500 时 判断请求失败
if (time > 3500) {
console.log('请求失败,时间:', time);
sb();
} else {
console.log('请求成功,时间:', time);
// 请求成功 调用cg函数
cg();
}
}, time)
}
fun(
// 参数1
() => {
console.log('第一次请求失败,不能继续访问');
},
// 参数2
() => {
console.log('第一次请求成功,可以继续访问');
// 第一次请求成功 发出第二次请求
fun(
() => {
console.log('第二次请求失败,不能继续访问');
},
() => {
console.log('第二次请求成功,可以继续访问');
// 第二次请求成功 发出第三次请求
fun(
() => {
console.log('第三次请求失败,不能继续访问');
},
() => {
console.log('第三次请求成功,可以继续访问');
}
)
}
)
}
)
第一次访问成功,继续下一次,到达第二次以后,访问失败,不再继续访问
Promise
Promise (契约) 是解决回调地狱的一种方法
Promise 的三个状态 1. 持续: pending 2. 成功: fulfilled 3. 失败: rejected
- resolve 会把我们这个 promise 状态转换为 成功
- reject 会把我们这个 promise 状态转换为 失败
一个 Promise 是对一个异步操作的封装,异步操作有 等待成功 、成功和失败三个状态 ,对应了Promise的三个状态
promise 只会发生两个转换 (一旦转换完成就不能再改变) 1. 持续 ==> 成功 2. 持续 ==> 失败
const P = new Promise( function(reslove,reject) {
// resolve 会把我们这个 promise 状态转换为 成功
// reject 会把我们这个 promise 状态转换为 失败 两个都是函数
const time = Math.ceil(Math.random() * 3000) + 2000; // 随机数 返回值作为倒计时器 时间
setTimeout(() => {
// 当时间大于3500 时 判断请求失败
if (time > 3500) {
console.log('请求失败,时间:', time);
reslove('失败!不能再继续访问')
} else {
console.log('请求成功,时间:', time);
// 请求成功 调用cg函数
reject('成功!可以继续访问');
}
}, time)
})
console.log(P);
then / catch
- then 在Promise 成功时触发,并且接受 resolve 时传递的参数
- catch 在Promise 失败时触发,并且会接受 reject 时传递的参数
const P = new Promise( function(reslove,reject) {
// resolve 会把我们这个 promise 状态转换为 成功
// reject 会把我们这个 promise 状态转换为 失败 两个都是函数
const time = Math.ceil(Math.random() * 3000) + 2000; // 随机数 返回值作为倒计时器 时间
setTimeout(() => {
// 当时间大于3500 时 判断请求失败
if (time > 3500) {
console.log('请求失败,时间:', time);
reject('失败!不能再继续访问')
} else {
console.log('请求成功,时间:', time);
// 请求成功 调用cg函数
reslove('成功!可以继续访问');
}
}, time)
})
P.then(function(res){
console.log('000',res);
}).catch(function(res){
console.log('111',res);
})
- 封装 Promise
function fun(){
const P = new Promise( function(reslove,reject) {
// resolve 会把我们这个 promise 状态转换为 成功
// reject 会把我们这个 promise 状态转换为 失败 两个都是函数
const time = Math.ceil(Math.random() * 3000) + 2000; // 随机数 返回值作为倒计时器 时间
setTimeout(() => {
// 当时间大于3500 时 判断请求失败
if (time > 3500) {
reject('失败!不能再继续访问')
} else {
// 请求成功 调用cg函数
reslove('成功!可以继续访问');
}
}, time)
})
return P; // 将 P 作为返回值 返回
}
fun().then((res) => {
console.log('第一次请求成功,可继续访问');
}).then((res) => {
console.log('第二次请求成功,可继续访问');
}).then((res) => {
console.log('第三次请求成功,可继续访问');
}).then((res) => {
console.log('第四次请求成功,可继续访问');
}).then((res) => {
console.log('第五次请求成功,可继续访问');
}).catch((res) => {
console.log('请求失败,不能继续访问');
})
async / await
作用: 能帮助我们把 异步代码, 写的和 同步代码一样
function fun() {
const P = new Promise(function (reslove, reject) {
// resolve 会把我们这个 promise 状态转换为 成功
// reject 会把我们这个 promise 状态转换为 失败 两个都是函数
const time = Math.ceil(Math.random() * 3000) + 2000; // 随机数 返回值作为倒计时器 时间
setTimeout(() => {
// 当时间大于3500 时 判断请求失败
if (time > 3500) {
reject('失败!不能再继续访问')
} else {
// 请求成功 调用cg函数
reslove('成功!可以继续访问');
}
}, time)
})
return P; // 将 P 作为返回值 返回
}
// 函数开头必须书写 async 表明内部可以书写 await
async function newFun() {
let p1 = await fun();
console.log(p1);
// 如果请求失败就执行 此行代码
console.log('失败!');
}
newFun(); // 调用async 声明的函数
await 后边需要跟着 promise,await 表示等到的意思, 执行到 fun() 虽然是异步的,但是因为有 await 关键字, 此时不会往下继续执行,而是等待 fun() 执行完毕, 在往下执行
- async/await 的问题
- 没有办法捕获到 错误, 只能接受 promise 的成功状态
- 如果报错, 会中断程序执行
- async/await 怎么抛出错误异常 ?
如果可能出错的代码比较少的时候可以使用try/catch结构来了处理,如果可能出错的代码比较多的时候,可以利 用async函数返回一个promise对象的原理来处理,给async修饰的函数调用后返回的promise对象,调用catch方 法来处理异常。
- async/await 的问题 解决方法 1 ( try...catch )
-
try...catch
首次执行的时候 会走 try 这个分支, 如果这个位置有报错,他会结束执行 try 分支, 然后走 catch 分支,如果再运行 try 分支的时候, 没有报错, 那么 catch 不会运行
-
function fun() {
const P = new Promise(function (reslove, reject) {
// resolve 会把我们这个 promise 状态转换为 成功
// reject 会把我们这个 promise 状态转换为 失败 两个都是函数
const time = Math.ceil(Math.random() * 3000) + 3000; // 随机数 返回值作为倒计时器 时间
setTimeout(() => {
// 当时间大于3500 时 判断请求失败
if (time > 3500) {
reject('失败!不能再继续访问')
} else {
// 请求成功 调用cg函数
reslove('成功!可以继续访问');
}
}, time)
})
return P; // 将 P 作为返回值 返回
}
async function newFun() {
try{ // 如果请求成功 执行此分支
let p1 = await fun();
console.log(p1);
}catch(error){
// 请求失败 执行此分支
console.log(error);
console.log('请求失败');
}
}
newFun(); // 调用async 声明的函数
-
async/await 的问题 解决方法 2
-
解决方法2: 更改 promise 的封装
原因: promise 执行 reject 时 async await 不能捕获到错误,
解决: 让这个 promise 不管什么情况 都返回 resolve
我们通过 返回的 参数, 区分现在是成功还是失败,开发中 对象内的 code 如果为0, 一般代表失败,对象内的 code 如果为1, 一般代表成功
-
function fun() {
const P = new Promise(function (reslove, reject) {
// resolve 会把我们这个 promise 状态转换为 成功
// reject 会把我们这个 promise 状态转换为 失败 两个都是函数
const time = Math.ceil(Math.random() * 3000) + 3000; // 随机数 返回值作为倒计时器 时间
setTimeout(() => {
// 当时间大于3500 时 判断请求失败
if (time > 3500) {
reslove({
code:0,
msg:'请求失败,不能继续访问'
})
} else {
// 请求成功 调用cg函数
reslove({
code:1,
msg:'请求成功,可以继续访问'
});
}
}, time)
})
return P; // 将 P 作为返回值 返回
}
async function newFun(){
const p1 = await fun();
// console.log(p1.code);
if(p1.code === 0){ // 如果code 为0 请求失败
console.log('您的网络有问题');
}else{ // 如果code 为1 请求成功 输出 msg 对应的值
console.log(p1.msg);
}
}
newFun();
转载自:https://juejin.cn/post/7167623174610223135