什么是同步?
同步和异步都是一种消息机制,同步是:A调用B,B处理获得结果才返回给A,A在这个过程一直等待B的处理结果,没有拿到结果之前,需要A一直等待和确认结果是否返回,拿到结果才继续执行下一步
什么是异步
A调用B,无需等待B的结果,B通过状态或者回调函数来处理,调用结果返回时,会以消息或者回调的方式通知调用者
异步请求都有哪些呢?
事件、定时器、网络请求
接下来说下处理异步请求的三种方法 回调函数、Promise、async,以一个动画实现为例子,说明三种方式的不同,
回调函数
<body>
<div class="box"></div>
<script>
let box = document.querySelector('.box')
function move(el,attr,val,cb){
let now = parseFloat(getComputedStyle(el)[attr])
let speed = (val - now)/Math.abs(val - now)
clearInterval(el.timer)
el.timer = setInterval(() => {
if(Math.abs(val - now)<=0){
clearInterval(el.timer)
cb && cb()
} else {
now+= speed
el.style[attr] = now+'px'
}
}, 10);
}
function moveBox(){
move(box,'left',100,function(){
move(box,'top',100,function(){
move(box,'left',0,function(){
move(box,'top',0,function(){
moveBox()
})
})
})
})
}
moveBox()
</script>
</body>
在上述代码,在一个动画执行结束之后,在回调函数用继续下一个动画,有多少个动画,就有多少个回调函数,这种就是回调地狱
回调地狱
最早我们处理异步消息通知,都是通过回调来处理,但是回调多了,代码的结构就必然嵌套层级特别多,造成可读性和维护性直线下降,这就是回调地狱
Promise
Promise不解决异步问题,解决的是异步写法的优化
上一个动画,可以利用promise.then方法的链式操作来写,看起来更加清晰
let box = document.querySelector('.box')
function move(el,attr,val){
console.log('move',attr,val)
let now = parseFloat(getComputedStyle(el)[attr])
let speed = (val - now)/Math.abs(val - now)
return new Promise((resolve)=>{
clearInterval(el.timer)
el.timer = setInterval(() => {
if(Math.abs(val - now)<=0){
clearInterval(el.timer)
resolve()
} else {
now+= speed
el.style[attr] = now+'px'
}
}, 10)
});
}
function moveBox(){
move(box,'left',200).then(()=>{
return move(box,'top',200)
}).then(()=>{
return move(box,'left',0)
console.log('left 0 ')
}).then(()=>{
console.log('top 0 ')
return move(box,'top',0)
}).then(()=>{
moveBox()
})
}
Promise的then方法返回的是一个promise对象 ,新的Promise对象执行的状态有三种:
1.默认情况:返回的是一个状态时resolve的Promise对象
2.返回的是非Promise对象,then返回的是一个状态是resolved的对象
3.当then的回调函数返回的是一个promise对象,then的返回值也会变成该promise对象
异步的终极方案 async await
let box = document.querySelector('.box')
function move(el,attr,val){
console.log('move',attr,val)
let now = parseFloat(getComputedStyle(el)[attr])
let speed = (val - now)/Math.abs(val - now)
return new Promise((resolve)=>{
clearInterval(el.timer)
el.timer = setInterval(() => {
if(Math.abs(val - now)<=0){
clearInterval(el.timer)
resolve()
} else {
now+= speed
el.style[attr] = now+'px'
}
}, 10)
});
}
async function moveBox(){
await move(box,'left',200)
await move(box,'top',200)
await move(box,'left',0)
await move(box,'top',0)
moveBox()
}
moveBox()