JS学习之同步和异步

249 阅读2分钟

什么是同步?

同步和异步都是一种消息机制,同步是: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()