本文深入解析JavaScript的单线程特性及异步处理机制,探讨网络请求与定时任务中的阻塞问题。通过对比回调函数与Promise,详解如何解决“回调地狱”,并介绍Promise.all和Promise.race在多接口并发场景下的具体应用与区别。
单线程
然而在实际开发中,若涉及网络请求或定时任务,同步等待操作完成会导致页面卡顿。为此,JavaScript引入了异步机制以优化用户体验。
异步
异步执行不会阻塞后续代码的运行,而是等待同步任务结束后再处理异步任务,这与同步代码会阻断执行流程形成对比。异步机制主要应用于网络请求和定时任务等场景。
异步是通过callback的方式实现的,在callback里面执行异步执行的代码,但是有一些场景比如我们有三个网络请求abc需要依次执行,在a的回调里发起b请求,在b的回调里发起c请求,这样会造成一种很混乱的写法,称之为回调地狱,可以试想一下,如果页面逻辑过于复杂,需要依次调用10个接口,那么代码的可读性会非常非常差,我们如果看到了别人的这种代码难免内心奔跑一万只神兽。
Promise基本用法:
let fun1 = function(flag){
return new Promise((resolve,reject)=>{
if(flag){
setTimeout(() => {
resolve("success")
}, 1000);
}else{
setTimeout(() => {
reject("fail")
}, 1000);
}
})
}
fun1(true).then((res)=>{
console.log(res)//success
}).catch((res)=>{
console.log(res)
})
fun1(false).then((res)=>{
console.log(res)
}).catch((res)=>{
console.log(res)//fail
})
上述代码展示了一个基础的Promise函数。该函数返回一个Promise对象,接收一个函数作为参数,该函数包含resolve和reject两个回调。当调用resolve()或reject()时,Promise状态发生变化。
若执行resolve(),则调用链中的then()方法将被触发,并接收resolve返回的参数;
若执行reject(),则调用链中的catch()方法将被触发,并接收reject返回的参数;
使用Promise重构上述三个网络请求的问题:
let callService = function(url){
return new Promise((resolve,reject)=>{
axios.get(url).then((res)=>{
resolve(res)
}).catch((err)=>{
reject(err)
})
})
}
const url1 = "/user/url1"
const url2 = "/user/url2"
const url3 = "/user/url3"
callService(url1).then((res)=>{
// do something
return callService(url2)
}).then(()=>{
// do something
return callService(url3)
}).then((res)=>{
// do something
}).catch((err)=>{
console.log(err)
})
采用上述方式重构后,代码结构扁平化,仅保持单层调用,从而避免了深层嵌套的回调地狱。
Promise.all
Promise.all用于将多个Promise实例包装为一个新的实例。当所有实例成功时,返回一个包含结果的数组;若任一实例失败,则立即返回失败的值。
Promise.all方法可有效处理日常开发中多接口并发调用的场景。
let p1 = new Promise((resolve, reject) => {
resolve('成功了')
})
let p2 = new Promise((resolve, reject) => {
resolve('success')
})
Promise.all([p1, p2]).then((result) => {
console.log(result) //['成功了', 'success']
}).catch((error) => {
console.log(error)
})
Promise.race
该方法用于实现多个接口的“赛跑”,返回最先完成(成功或失败)的那个结果。
Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error)
})
以上是对JavaScript异步与单线程机制的详细解析,更多相关技术文章请持续关注本站。