异步

作者: 广州芦苇科技web前端 | 来源:发表于2018-12-14 23:33 被阅读0次

    标签: 异步


    单线程

    说到异步那么就必须要先了解单线程这个概念。简单来说单线程就是:只有一个线程,在同一个时间内只能够操作一件事情。JavaScript就是单线程的。

    那么为什么JavaScript是单线程的呢?

    这里主要原因就是DOM渲染的问题,我们都知道当浏览器接收到页面后会进行页面的渲染,而JS是可以修改DOM结构的,所以在JS执行的时候,浏览器DOM渲染是会暂停的,如果JS在执行的时候浏览器的DOM渲染没有停止,那么就会有可能出现浏览器和JS同时修改一个DOM,这个时候就有了冲突,所以说浏览器的DOM渲染和JS的执行是在一个线程之内的。

    既然浏览器和JS有可能会同时修改一个DOM元素,那么两段不同的JS代码也可能会同时修改一个DOM,所以为了避免这样的情况发生JavaScript就必须是单线程的并且和浏览器的渲染也是在一个线程中的。

    在HTML5中的webworker支持多线程,但是它不能够访问DOM

    单线程所带来的问题

    因为单线程规定所有的任务在同一时间内只能够做一件事情,前面的任务没有做完后面的任务就无法进行。这样子会带来许多的问题。

    如下面所示,如果我希望在打印了100之后等待1s在打印200,那么按照单线程的规定,在这1s钟的时间内我无法做其他的事情,只能等待,等执行完之后才能做接下来的事情。这样的体验是非常不好的。

    console.log(100)
    setTimeout(function () {
        console.log(200)
    }, 10000)
    console.log(300)
    console.log(400)
    

    同时在ajax请求的时候,我们无法知道请求什么时候能够执行完毕,那么如果按照单线程的规定我们就只能等待ajax的请求执行完之后才能执行其他的事情。

    而异步就是解决单线程所带来的这些问题的一种方案。

    异步

    异步的一个简单的理解就是当碰到需要等待一段时间之后再执行的代码的时候,先把这段代码放到一边,先执行接下来的代码,然后在等待时间到了之后再去执行之前的那段代码。

    console.log(100)
    setTimeout(function () {
        console.log(200)
    }, 10000)
    console.log(300)
    console.log(400)
    

    由于setTimeout在js中是一个异步的函数,所以我们上面这一段代码就不会是向之前我们所描述的那样,在碰到第二句代码的时候会发现它需要在1秒钟之后才会执行,那么这个时候浏览器就会先执行下面的代码,然后等到1s钟之后才会去打印200。

    一般在碰到异步操作的时候通常是利用回调函数来处理,在上面的例子中setTimeout的第一个参数就是回调函数,这里的意思是在一秒钟之后执行回调函数。

    在执行ajax操作的时候都是需要等待服务端返回消息,所以一般情况下ajax操作都是异步的,利用回调函数来进行ajax请求成功之后的操作。

    异步的优缺点

    优点:

    • 异步可以非常高效简单的解决JavaScript单线程所带来的问题

    缺点:

    • 异步的代码不会按照书写的顺序执行,可读性差。
    • callback不容易模块化,回调函数不宜写得过于复杂,这样会出现耦合度过高的问题。

    event-loop

    在上面我们简单的介绍了一下实现异步的思想,那么接下来我们就来看看在JS中实现异步的具体解决方案。

    在JS中实现异步的具体解决方案就是事件轮询(event-loop),事件轮询的简单解释就是:

    • 同步代码直接执行
    • 异步函数先放在异步队列中
    • 待同步函数执行完毕之后,轮询执行异步队列中的函数

    这里可以认为在程序中设置了两个线程,一个负责程序本身运行,称为“主线程”;另外一个负责主线程与其他进程的通信,被称为“event-loop线程”(也可以称为消息线程)

    setTimeout(function () {
        console.log(100)
    })
    console.log(200)
    

    按照我们之前的解释,上面这段代码是怎样执行的呢?

    首先会执行所有的同步代码(打印200),也就是说所有的同步代码都是在主进程中的,当同步代码执行完之后,会去查看异步队列中是否有需要执行的内容,然后发现在异步队列中有一个函数,然后执行这个函数(打印100)。

    下面来看一个复杂一点的例子:

    setTimeout(function () {
        console.log(1)
    },100)
    setTimeout(function () {
        console.log(2)
    })
    console.log(3)
    

    现在我们来分析一下上面的代码是如何执行的,首先还是一样先执行同步代码(打印3),然后由于第二个setTimeout没有延迟时间,那么第二个函数就会立即被放入异步队列中,这个时候同步代码执行完了那么就会执行第二个定时器中的代码(打印2),由于第一个setTimeout有100毫秒的延迟,这个函数会在100毫秒之后放入异步队列中并且执行(打印1)。

    image

    往期精彩回顾


    李成文 广州芦苇科技web前端工程师

    相关文章

      网友评论

          本文标题:异步

          本文链接:https://www.haomeiwen.com/subject/wbznhqtx.html