线程机制与事件机制

进程与线程

进程

进程:程序的一次执行,它占有一片独有的内存空间可以,通过windows任务管理器查看进程
eg:
在这里插入图片描述

线程

是进程内一个独立执行的单元
是程序执行的一个完整流程
是CPU的最小调度单元

eg:

在这里插入图片描述

  • 一个程序可以有多个进程
    eg:chrome进程
    在这里插入图片描述

  • 单线程和多线程
    单线程:一个进程中只有一个线程
    多线程:一个进程中有多个线程
    单线程和多线程局限在一个进程之内。

进程和线程之间的关系

  • 应用程序必须运行在某个进程的某个线程上
  • 一个进程中至少有一个运行的线程: 主线程,进程启动后自动创建
  • 一个进程中也可以同时运行多个线程,我们会说程序是多线程运行的
  • 一个进程内的数据可以供其中的多个线程直接共享
  • 多个进程之间的数据是不能直接共享的(进程的内存是独立的)
  • 线程池(thread pool):保存多个线程对象的容器,实现线程对象的反复利用
    从线程池中拿出线程来执行程序,程序执行完成之后在将线程放回去。

可以这样简单理解进程与线程的关系:

  • 进程:进程负责为程序的运行提供必备的环境——进程就相当于工厂中的车间
  • 线程:线程计算机中的最小的计算单位,线程负责执行进程中的程序——线程就相当于工厂中的工人

相关问题

多进程与多线程

  • 多进程运行:一应用程序可以同时启动多个实例运行
  • 多线程:在一个进程内,同时有多个线程运行

单线程与多线程运行的区别

  • 多线程:
    优点:能有效提升CPU的利用率创建多线程开销
    缺点:线程间切换开销、死锁与状态同步问题
    单核的多线程是分时执行的,不同时刻执行不同的线程,所以会产生线程间切换开销

  • 单线程
    优点:顺序编程简单易懂
    缺点:效率低

JS是单线程还是多线程

js是单线程运行的。——就一个主线程

问题:如果页面中一个地方加载运行,则整个页面都是卡死状态
解决:使用H5中的 Web Workers可以多线程运行。利用Web Workers产生分线程进行执行。

浏览器是单线程还是多线程

都是多线程运行的

浏览器是单进程还是多进程

有的是单进程:firefox、老版IE
有的是多进程:chrome、新版IE

浏览器内核

定义

浏览器内核是支撑浏览器运行的最核心的程序。

  • 不同浏览器的内核是不一样的:
    Chrome,Safari : webkit
    firefox : Gecko
    IE: Trident
    360,搜狗等国内浏览器:Trident + webkit

组成内核的不同模块

主线程模块:

  • js引擎模块∶负责js程序的编译与运行
  • html,css文档解析模块:负责页面文本的解析
  • DOM/CSS模块:负责dom/css在内存中的相关处理(将相关的标签转化成对象)
  • 布局和渲染模块:负责页面的布局和效果的绘制(参照内存中的Dom对象)

分线程模块:

  • 定时器模块:负责定时器的管理
  • DOM事件响应模块:负责事件的管理
  • 网络请求模块:负责ajax请求

定时器

定时器并不能保证真正定时执行。
一般会延迟一点点,这点延迟可以接受;但是若果有特殊情况,延迟很多的时候就不可以接受了。

  • 延迟一点点:
<body>
    <button id="btn">点击按钮启动定时器</button>
    <script>
      document.getElementById("btn").onclick = function () {
        var start = Date.now();
        console.log("定时器启动前");

        setTimeout(function () {
          console.log("定时器执行了", Date.now() - start);
        }, 200);

        console.log("定时器启动后");
      };
    </script>
  </body>

在这里插入图片描述

  • 延迟很多
  <body>
    <button id="btn">点击按钮启动定时器</button>
    <script>
      document.getElementById("btn").onclick = function () {
        var start = Date.now();
        console.log("定时器启动前");

        setTimeout(function () {
          console.log("定时器执行了", Date.now() - start);
        }, 200);

        console.log("定时器启动后");
        for (var i = 0; i < 1000000000; i++) {
           
        }
      };
    </script>
  </body>

在这里插入图片描述

  • 定时器在哪执行?
    主线程执行,因为JS是单线程的只有一个主线程。
  • 产生此现象的原因——事件循环模型

JS单线程执行的验证

alert

alert作用:会暂停主线程的执行,也会暂停计时器; 点击确定之后恢复程序执行和计时
代码:

  <body>
    <button id="btn">点击按钮启动定时器</button>
    <script>
      setTimeout(function (){
         console.log('timeout 2222')
         alert("22222222")
      },2000)
      setTimeout(function (){
         console.log('timeout 1111')
         alert("111111111")
      },1000)
      function fn (){
         console.log('fn()')
      }  
      console.log('alert之前')
    //  alert作用会暂停主线程的执行,也会暂停计时器
    // 点击确定之后恢复程序执行和计时
      alert("--------")
      console.log('alert之后')     
    </script>
  </body>

代码分类

  • 初始化代码
  • 回调代码
    eg:
 setTimeout(function (){
         console.log('timeout 2222')
         alert("22222222")
      },2000)

setTimeout 属于初始化代码;
function (){
console.log(‘timeout 2222’)
alert(“22222222”)
} 属于回调代码

js引擎执行代码的基本流程

  • 先执行初始化代码:包含一些特别的代码
    • 设置定时器:绑定回调函数,但是不会执行回调函数
    • 绑定dom事件监听:绑定回调函数,但是不会执行回调函数
    • 发送ajax请求
  • 后面在某个时刻才会执行回调代码——异步执行
    eg:
     setTimeout(function (){
         console.log('timeout 2222')
      },2000)
      setTimeout(function (){
         console.log('timeout 1111')
      },1000)
      setTimeout(function (){
         console.log('timeout 0000')
      },000)
      function fn (){
         console.log('fn()')
      }  
      console.log('alert之前')
    //  alert作用会暂停主线程的执行,也会暂停计时器
    // 点击确定之后恢复程序执行和计时
      alert("--------")
      console.log('alert之后')

输出顺序:
在这里插入图片描述

为什么js设置为单线程

如果有多个线程对一个DOM对象进行操作,可能会出现冲突。

事件循环模型

模型的2个重要组成部分:

  • 事件(定时器/DOM事件/Aja)管理模块
  • 回调队列(存放待处理的的回调函数)

模型原理图:
在这里插入图片描述
模型的运转流程:

  • 执行初始化代码,将事件回调函数交给对应模块管理
  • 当事件发生、到达时间点后,管理模块会将回调函数及其数据添加到回调列队中
  • 只有当初始化代码执行完后(可能要一定时间),才会遍历读取回调队列中的回调函数执行

相关概念

执行栈

所有的代码都在此空间执行。
即:
在这里插入图片描述

浏览器内核

js引擎模块:在主线程处理
其它模块:在主/分线程处理

回调队列(callback queue)

在这里插入图片描述
又称为 任务队列、消息队列、事件队列

事件轮询 event loop

执行完初始化代码之后,需要从回调队列中循环取出回调函数放入执行栈中处理(一个接一个),该过程就成为事件轮询。

请求响应

在这里插入图片描述

H5 Web Workers(多线程)

单线程问题

当一个元素在计算原型,整个页面都不能操作。
eg:

  <body>  
   <input type="text" name="" id="number" placeholder="数值">
   <button id='btn'>计算</button>
    <script>
    function fibonacci(number){
        // 1 1 2 3 5 8 13
       return number<=2 ? 1:fibonacci(number-1)+fibonacci(number-2)
    }
    
    var input =document.getElementById('number')
    document.getElementById('btn').onclick =function(){
        var number = input.value
       var result=fibonacci(number)
       alert(result)
    }
          
    </script>
  </body>

当输入一个较大的数字的时候,递归调用需要一定的时间,界面就处于加载的状态整个页面都不能操作。

WebWorks介绍

Web Workers是HTML5提供的一个javascript多线程解决方案
实现原理:

  • 我们可以将一些大计算量的代码交由web Worker运行而不冻结用户界面
  • 但是子线程完全受主线程控制,且不得操作DOM。(只有主线程测i能操作DOM)
    所以,这个新标准并没有改变JavaScript单线程的本质

WebWorks使用

  1. 创建在分线程执行的js文件
  2. 在主线程中的js中发消息并设置回调

eg:
work.js文件

function fibonacci(number){
    // 1 1 2 3 5 8 13
    return number<=2 ? 1:fibonacci(number-1)+fibonacci(number-2)
}

var onmessage = function (event) {
    var number = event.data
    console.log("分线程接收到主线程发送的数据:" + number)
    // 计算
    var result = fibonacci(number)
    postMessage(result)
    console.log("分线程向主线程返回的数据:" + result)
}

.html文件

<!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>
  </head>
  <body>  
   <input type="text" name="" id="number" placeholder="数值">
   <button id='btn'>计算</button>
    <script>

    var input =document.getElementById('number')
    document.getElementById('btn').onclick =function(){
       var number = input.value


      //  创建一个worker对象,存放js文件
      var worker = new Worker('./work.js')

      // 向分线程发送消息
      worker.postMessage(number)
      console.log("主线程向分线程发送的数据:"+ number)

      // 接收消息,注册监听
      worker.onmessage = function (event){
        console.log("主线程接收分线程返回的数据:"+event.data)
        alert(event.data)
      }
    }
          
    </script>
  </body>
</html>

var worker = new Worker( 'worker.js ’ );
worker . onMessage = function(event){event.data}:用来接收另一个线程发送过来的数据的回调worker.postMessage(data) :向另一个线程发送数据

输出:
在这里插入图片描述

问题:JS文件的this是谁?
测试输出是DedicatedWorkerGlobalScopeDedicatedWorkerGlobalScope 就是分线程的全局对象,onmessage、postMessage属性就在上面,可以直接调用该属性。

function fibonacci(number){
    // 1 1 2 3 5 8 13
    return number<=2 ? 1:fibonacci(number-1)+fibonacci(number-2)
}

console.log(this)
var onmessage = function (event) {
    var number = event.data
    console.log("分线程接收到主线程发送的数据:" + number)
    // 计算
    var result = fibonacci(number)
    postMessage(result)
    console.log("分线程向主线程返回的数据:" + result)
}

在这里插入图片描述
注意 :
alert是window的方法,分线程的全局对象不是window,自然不能调用alert了。
而 console是浏览器提供的谁都可以用。

所以由于分线程中的全局对象不再是window,所以在分线程中不可能更新界面(更新界面需要使用doument属性,而doument是window的属性,所以看不见)

图解

在这里插入图片描述

分线程的作用

解决一些费时间的计算

分线程缺点

慢(只是不阻塞主线程而已)
不能跨域加载JS
worker内代码不能访问DOM(更新UI)
不是每个浏览器都支持这个新特性

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值