zoukankan      html  css  js  c++  java
  • JS高级——浏览器的线程

    基本概念

    1、js的执行过程是单线程的模式,也就是同步进行,只有前面的代码执行完了才会往下面执行

    2、但是执行js代码也只是浏览器的线程之一所负责的事情,这个线程被称为js引擎,浏览器还具有其他线程:界面渲染线程(UI)、浏览器事件触发线程(控制交互,响应用户)、http请求线程(处理请求,而ajax发送请求则会委托浏览器新开一个http线程)、EventLoop轮询线程(负责轮询消息队列)

    3、浏览器中js代码的作用:执行JavaScript代码 、对用户的输入(包含鼠标点击、键盘输入等等)做出反应 、处理异步的网络请求

    js单线程

    1、单线程的含义是js只能在一个线程上运行,也就说,js同时只能执行一个js任务,其它的任务则会排队等待执行。

    2、js是单线程的,并不代表js引擎线程只有一个。js引擎有多个线程,一个主线程,其它的后台配合主线程。

    3、多线程之间会共享运行资源,浏览器端的js会操作dom,多个线程必然会带来同步的问题,所有js核心选择了单线程来避免处理这个麻烦。js可以操作dom,影响渲染,所以js引擎线程和UI线程是互斥的。这也就解释了js执行时会阻塞页面的渲染

    js消息队列

    1、JavaScript运行时,除了一个运行线程,引擎还提供一个消息队列,里面是各种需要当前程序处理的消息。新的消息进入队列的时候,会自动排在队列的尾端

    2、单线程意味着js任务需要排队,如果前一个任务出现大量的耗时操作,后面的任务得不到执行,任务的积累会导致页面的“假死”。这也是js编程一直在强调需要回避的“坑”

    js执行任务方式

    1、首先js任务分两种:同步任务、异步任务

    2、同步任务:在主线程排队支持的任务,前一个任务执行完毕后,执行后一个任务,形成一个执行栈,线程执行时在内存形成的空间为栈,进程形成堆结构,这是内存的结构。执行栈可以实现函数的层层调用。注意不要理解成同步代码进入栈中,按栈的出栈顺序来执行。

    3、异步任务:会被主线程挂起,不会进入主线程,而是进入消息队列,而且必须指定回调函数,只有消息队列通知主线程,并且执行栈为空时,该消息对应的任务才会进入执行栈获得执行的机会。

    4、主线程说明:

    (1)所有同步任务都在主线程上执行,形成一个执行栈。 
    (2)主线程之外,还存在一个”任务队列”(消息队列)。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。 
    (3)一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”(消息队列),看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。 
    (4)主线程不断重复上面的第三步。

    5、消息队列说明:

    (1)消息队列队列(或者叫任务队列)是一个事件的队列,IO响应时(鼠标点击等输入输出设备的操作),会往队列中添加一个消息,此时说明相关的异步代码到了执行的时机,可以进入主线程的执行栈了。

    (2)主线程读取消息队列,可以读取到对应的事件。

    (3)消息队列可以响应IO事件,还有用户产生的事件(比如点击鼠标,页面滚动),只要指定了回调函数,就会进入消息队列,等待EventLoop轮询线程处理,是否可以进入主线程的执行栈。

    (4)消息和回调函数相互联系的含义:主线程读到消息,就会执行相应的回调函数;进入消息队列的消息,必须对应相应的回调函数,否则这个消息会被丢弃不会进入消息队列。

    (5)消息队列是一个先进先出的队列结构,这就决定了它的执行顺序,先产生的消息会被主线程先读取,会不会执行则会先检查一下执行时间,因为存在setTimeout等定时函数,这类事件产生的消息进入到消息队列,被执行的时机取决与它在队列中的位置和执行时间有关。【使用setTimeout能够避免阻塞UI线程就是这个原因】。

    5、需要注意的是:执行栈中的代码(同步任务),总是在读取”任务队列”(异步任务)之前执行。

    EventLoop

    1、主线程从”任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。

    2、简单说,浏览器的两个线程:一个负责程序本身的运行,称为”主线程”;另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为”Event Loop线程”(可以译为”消息线程”)。

    3、由于js是运行在单线程上的,所有浏览器单独开启一个线程来处理事件消息的轮询,避免阻塞js的执行。

    异步代码执行逻辑

    1、每当遇到I/O的时候,主线程就让EventLoop线程去通知相应的I/O程序,然后接着往后运行,所以不存在等待时间。等到I/O程序完成操作,EventLoop线程把消息添加到消息队列,主线程就调用事先设定的回调函数,完成整个任务。

    2、js的ajax是new XMLHttpRequest()对象实现的,浏览器会新开一个线程来处理http请求,这就是ajax能够实现局部刷新的同时,还能响应用户交互的原因。

    定时器

    1、前面也提到了定时器,定时器是会在进入消息队列,这也就和异步代码的执行逻辑一样了。它在”消息队列”的尾部添加一个消息,因此要等到同步任务和”消息队列”现有的任务都处理完,才会得到执行的机会,还要看定时器设置的时间是否到了才会执行。

    <script>
        for(var i = 0 ; i < 10; i++){
           setTimeout(function(){
               console.log(i);//打印10次10
           },0);
        }
    </script>

    所以,只有等到主线程的任务执行完之后,setTimeout中的事件才会被执行,虽然时间间隔是0秒,但是必须等主线程任务完成,所以最后打印的都是10

    2、可以用闭包来解决问题,每次执行for循环的时候,把函数作为返回值给setTimeout作为参数,函数里面存着从for循环里面拿到的每一个值,下面代码会返回多个函数,每个函数的j值都不一样

    <script>
        for(var i = 0; i< 3; i++){
            function foo(j){
            // var j;
            // j = 实参
            //j = i
                return function(){
                    console.log(j);
                };
            }
            //0
            var f = foo(i);
            setTimeout(f, 0);
        }
    </script>

    参考:

    http://blog.csdn.net/w2765006513/article/details/53743051

    https://www.cnblogs.com/haodawang/articles/5850822.html

  • 相关阅读:
    关于maven的一些记录
    3des和tomcat部署
    java串口通讯
    mina自定义编解码
    Linux 下关闭防火墙设置
    查看本机IP
    linux修改localhost方法
    centos 6.5下使用中文输入法
    linux:can't save files
    ng-model取不到值的问题
  • 原文地址:https://www.cnblogs.com/wuqiuxue/p/8342121.html
Copyright © 2011-2022 走看看