异步--我想跟你谈谈

1,058 阅读4分钟

大家好,我是不想干开发,什么都想试试的布布。今天,又是39摄氏度的一天,太热了(掘金社区麻烦安一下空调)。为了降降温,写点什么吧!想来想去,就我这点水平,只剩下异步可以浅浅的聊聊了。那咱就开始吧!

同步异步概念

单线程

  • js是单线程

    • 单线程:同一时间只能做一件事情

    • 为什么是单线程?

      • 为了避免复杂性,例如同一时间操作相同DOM需考虑优先级一类的

同步和异步

  • 同步和异步

    • 同步和异步是一种消息通知机制

      • 同步阻塞: A调用B,B处理获得结果,才返回给A。A在这个过程中,一直等待B的处理结果,没有拿到结果之前,需要A(调用者)一直等待和确认调用结果是否返回,拿到结果,然后继续往下执行。

      做一件事,没有拿到结果之前,就一直在这等着,一直等到有结果了,再去做下边的事

          console.log('你');
          console.log('我');
          console.log('他');
          //执行结果为 你 我 他 按照代码执行顺序输出结果
      
          console.log('你');
          // callback 回调函数
          function test(cb){//一般情况下,该函数是已经被封装好的函数,不允许直接修改,所以在创建时,可以预留一个回调函数用于实现同步
              setTimeout(()=>{
                  console.log('他');
                  cb && cb();
              },1000)
          }
          test(function(){
              console.log('我');
          });
          //执行结果为 你 他 我
      
      • 异步非阻塞: A调用B,无需等待B的结果,B通过状态,通知等来通知A或回调函数来处理。

      做一件事,不用等待事情的结果,然后就去忙别的了,有了结果,再通过状态来告诉我,或者通过回调函数来处理。

          console.log('你');
          // callback 回调函数 下一部分将会码文字解释
          function test(){
              setTimeout(()=>{
                  console.log('他');
              },1000)
          }
          test();
          console.log('我');
          //执行结果为 你  我  他
      

异步处理方案

回调

  • 回调

    • 上面例子通过回调函数来处理异步,但是容易造成回调地狱

      • 回调地狱:函数作为参数层层嵌套,前后关联性特别强(第一个回调出现异常不执行,后续回调将都不会执行且无法捕捉到异常)。回调地狱会导致代码可读性及可维护性变差。
    function test(cb){
        console.log('回调地狱');
        cb && cb();
    }

    test(function(){
        test(function(){
            test(function(){
                console.log("执行完成了");
            })
        })
    })

运行结果: image.png

自定义事件

方块运动实现

  • 回调运动框架方块的运动
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box{
            width: 100px;
            height: 100px;
            background: blue;
            position:absolute;
            left: 0px;
            top: 0px;
        }
    </style>
</head>
<body>
    <div class="box"></div>
</body>
<script>
function move(el,direction,position,cb){
    let start = parseInt(getComputedStyle(el,null)[direction]);
    let speed = 5 * (position>start?1:-1);
    setTimeout(()=>{
        start+= speed;
        if(start===position){
            // console.log("运动完成");
            cb && cb()
        }else{
            el.style[direction] = start + "px";
            move(el,direction,position,cb);
        }
    },10)
}
let el = document.querySelector(".box");
move(el,'left',300,function(){
    move(el,'top',300,function(){
        move(el,'left',0,function(){
            move(el,'top',0,function(){
                console.log("运动完成");
            })
        })
    })
});
</script>
</html>

没有结果动画,不想截。。。。。

promise使用

  • ES6 Promise 对象

    • 两种参数:then的2个参数;onresolove 和 onreject;

    • ES6的Promise对象是一个构造函数,用来生成Promise实例。 所谓Promise对象,就是代表了未来某个将要发生的事件(通常是一个异步操作)。 它的好处在于,有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数

Promise对象的三种状态 pending 、resolve 和 reject

    let p1=new Promise(()=>{})
    console.log(p1);
    let p2 = new Promise((resolve,reject)=>{
        resolve("success");
    })
    console.log(p2);
    let p3 = new Promise((resolve,reject)=>{
        reject("err");
    })
    console.log(p3);

可以看到返回值如下:

image.png

then方法

  • then 方法

    • then的返回值,会返回一个新的 Promise 对象,实现链式操作, 但是状态会有几种情况:

      • then 的回调函数中没有返回值,then就会返回一个状态为: resolved 的 promise 对象
              let p = new Promise((resolve,reject)=>{
                  resolve("success");
              })
              let p2=p.then(res=>{
      
              })
              console.log(p2);
              p2.then(res=>{
                  console.log(res)
              })
      

    image.png

    • then 的回调函数返回值是 非 promise 的值, then就会返回一个状态为: resolved 的 promise 对象,另外会把返回值,传递给 下一个 then
            let p = new Promise((resolve,reject)=>{
                resolve("success");
            })
            let p2=p.then(res=>{
                return "成为优秀的人 请务必加油";
            })
            console.log(p2);
            p2.then(res=>{
                console.log(res)
            }) 
    

    image.png

    • then 的回调函数返回值是 promise 对象,then 就直接返回这个 promise 对象,具体的状态可以由我们自己定义,具体传递的值,也由我们自己定义
        let p = new Promise((resolve,reject)=>{
            resolve("success");
        })
        let p2 = p.then(res=>{
            return new Promise((resolve,reject)=>{
                resolve("今天的你也辛苦啦!");
            })
        })
        p2.then(res=>{
            console.log(res);
        })
        console.log(p2);
    

    image.png

    • Promise 下的方法:resolve、reject、all(收集成功后的结果返回一个数组,结果都必须是resolve的,不然收集不到结果。可以选择用allSettled)、race(谁执行的快,先抛出谁的结果)、finally(执行完成就会调用执行无论成功或失败)

async及await 改造promise

  • Async 函数 和 await 改造promise;
  • try及catch方法捕获错误
    async function fn(){

    }
    console.log(fn());

结果:async函数也是基于promise构建的,generator分步执行 image.png 下一节将会手写promise,近一步了解其原理以及promise下的方法。