js同步异步

Last updated on 8 months ago

什么是同步异步

  • 同步编程

    同步,指同一时序线、同一线程,多个操作按顺序进行,默认情况下,很多语言都是同步进行的,而当我们遇到执行较长的代码时,同步会让我们的程序造成阻塞

    1
    2
    3
    4
    5
    6
    7
    8
    // 定义一个阻塞函数
    function sleep(milliSeconds){
    var startTime = new Date().getTime()
    while (new Date().getTime() < startTime + milliSeconds)
    }
    // 阻塞3s
    sleep(3000)
    console.log(123)

    执行,发现等待3s后,控制台才有输出。程序发生了阻塞

  • 异步编程

    同理,异步就是不在同一线程、时许线上,相当于俩边同时进行,但是我们知道,js是单线程的,单线程要怎么做到异步呢?

    虽然js是单线程的,但浏览器不是,浏览器在接受到异步请求后会交给其他线程执行,执行完成后返回。

异步的实现方式

在js中异步有两种实现方式:

  • 回调函数

    比如setTiemoUt()函数,我们可以输入一个回调函数和一个时间作为参数,执行setTimeout()的时候会立即返回,执行下方的代码,在计时结束后会返回回调函数

    1
    2
    3
    4
    setTiemout(()=>{
    console.log("我是回调")
    },3000)
    console.log("我会比回调先执行")

    回调函数非常简单好理解,但如果我们需要依次执行异步操作,就会被写成这样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    setTimeout(()=>{
    console.log("等3s")
    setTimeout(()=>{
    console.log("再等3s")
    setTimeout(()=>{
    console.log("还等3s")
    },3000)
    },3000)
    },3000)

    这种被称为函数瀑布,回调地狱,为了解决这个问题,ES6引入了promise

  • Promise

    直译为承诺,也就是先承诺,再通过回调兑现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const promise = new Promise((resolve, reject)=>{
    // 异步操作
    resolve("成功信息")
    reject("错误信息")
    }).then((result)=>{
    // 操作成功后
    }).catch((error)=>{
    // 操作失败后
    }).finally(()=>{
    // 无论成功失败都会调用
    })

    Promise的构造函数接受一个回调函数作为参数,回调函数的参数有两个:resolevereject

    在promise中,**一定要调用resolve()reject()**,resolve()用于返回成功信息,reject()用于返回错误信息,在执行后会对应的进入到then()方法或catch()方法,如果不写,promise会一直处于pending等待状态

    Promise的方法有

    • then():用于处理成功状态的回调
    • catch():用于处理失败状态的回调
    • finally():无论成功失败都会执行的回调

    而对于上面的回调地狱,promise提供了promise链来实现,将左右方向延申变为了上下方向

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
    console.log("3s");
    resolve();
    }, 3000);
    })
    .then(() => {
    // 返回一个promise对象
    return new Promise((resolve, reject) => {
    setTimeout(() => {
    console.log("又3s");
    resolve();
    }, 3000);
    });
    })
    .then(() => {
    setTimeout(() => {
    console.log("还3s");
    }, 3000);
    });
    console.log("他们是异步,我是第一个执行的");

  • async/await语法糖

    这是基于Promise的语法糖,通过async关键字可以将函数标记为异步函数

    1
    2
    3
    async function() {

    }

    await关键字用于async内部,用于等待另一个promise函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

    async function ff() {
    await delay(3000);
    // 等待上面异步结束后才执行
    console.log("3s过去了");
    }

    ff();
    console.log("我最先执行");