什么是链式调用
链式调用,其实就是前端开发中常见的.then()/.catch()这种形式来处理异步调用的方式。它是随着Promise的产生而产生的,要了解链式调用,就得先了解什么是Promise。就像下面这个简单示例:
axios.get('/xxx/xxx')
.then(res=>{
//处理调用成功时的结果
})
.catch(err=>{
//调用失败时的处理
})
什么是Promise?
它是一种风格
抽象地来说,它可以称为一种“风格”。因为它的出现改变了以前传统上处理异步操作的编程风格。原本在JavaScript中,是使用回调函数(callback)来处理异步操作的,而这种方式变得难以维护。尤其是遇到多层嵌套的回调时,容易出现“回调地狱”(callback hell)问题。
而Promise的诞生提供了我们所熟知的链式调用(即.then()和.catch()方式),来处理异步操作。这是一种新的风格,它有效地解决了回调嵌套问题,是的代码更加结构化。
它是一个对象
而具体地来说,它其实是JavaScript的一个表示异步操作的对象。它用于表示一个“此时已开始但未完成,但预计会在未来的某个时间完成”的操作,同时提供了链式调用这种结构化的方式来进行处理。
它有三种状态:
Pending(进行中): 初始状态,既不是成功也不是失败。
Fulfilled(已成功): 表示操作成功完成。
Rejected(已失败): 表示操作失败。
这三种状态是不可逆转的,一旦从一个状态跳到下一个状态,就不能再改变了。
它允许你注册回调函数,操作成功或失败时,会调用这些回调函数。
简单示例:
// 创建一个 Promise 实例
const myPromise = new Promise((resolve, reject) => {
// 模拟一个异步操作(例如:网络请求)
setTimeout(() => {
const success = true; // 假设操作成功
if (success) {
resolve('操作成功!'); // 如果成功,调用 resolve
} else {
reject('操作失败!'); // 如果失败,调用 reject
}
}, 1000);
});
// 使用 .then() 和 .catch() 来处理结果和错误
myPromise
.then(res=> {
// 处理成功时的结果
})
.catch(err=> {
// 处理错误
});
什么是async/await?
自从Promise出现后,尽管解决了回调地狱的问题,但在写多个连续异步操作时,代码会变得冗长,让人难以阅读。
此时async/await就应运而生,ES8/ES2017引入了async/await。它的出现就是用来改善Promise的写法的,目的就是让代码变得更加直观易懂。可以说它是Promise的语法糖。
特点与使用方式
它的特点其实就在于async和await这两个关键字:
async 关键字: 用于声明一个函数为异步函数。异步函数会默认返回一个 Promise。
await 关键字: 用于暂停异步函数的执行,直到 Promise 被解决(resolved)或拒绝(rejected)。await 只能在 async 函数中使用。
async/await简单示例:
async function getData() {
try {
//获取用户列表
const res= await axios.get('/api/user/list');
console.log('用户列表:', res.data);
//获取某个具体的用户详情
const userDetailRes= await axios.get(`/api/data/${res.data.get(0).id}`);
console.log('用户详情:', userDetailRes.data);
} catch (err) {
console.error('错误:', err);
}
}
getData();
以上写法改为链式调用则为:
axios.get('/api/user/list')
.then(res => {
console.log('用户列表:', res.data);
// 返回一个新的 Promise 以便进行下一步的链式调用
return axios.get(`/api/data/${res.data.get(0).id}`);
})
.then(userDetailRes=> {
console.log('用户详情:', userDetailRes.data);
})
.catch(err=> {
console.error('错误:', err);
});
以上的代码,由于调用次数太少,可能无法很明显地体现复杂度的优化。
但可以看到,这种代码风格更加接近同步逻辑,其中try…catch是很常见的异常处理机制。一定程度上是优化了可读性。
哪种好?选择哪种?
总的来说,不能完全判断哪种更好,在实际使用还是可以按习惯或者项目要求来判断使用哪种方式。
而从产生背景来讲,async/await是优于链式调用的,因为它本身是Promise的优化。一般来说,嵌套层数较少时,两者区别可能并不大,但是如果遇到嵌套层数过多的情况,可以考虑使用async/await的风格来进行优化。
注意,由于async/await 是 ES8 (ES2017) 的特性,在一些旧的浏览器或者其他一些旧JavaScript运行环境中可能存在不支持的情况。
所以个人觉得,如果要考虑兼容性,可以优先考虑使用链式调用的方法就好。如果不需要考虑兼容性,可以优先使用async/await的方式。