js 高级笔记(线程机制与事件机制)

177 阅读6分钟

@[TOC]

线程机制与事件机制

进程与线程

1. 进程(process):

程序的一次执行,它占有一片独有的内存空间 可以通过windows任务管理器查看进程

2. 线程(thread):

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

3. 图解

image.png

4. 相关知识:

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

5.相关问题

何为多线程?

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

比较单线程与多线程?

多线程:
优点:
  • 能有效提升CPU效率
缺点:
  • 创建爱你多线程开销
  • 线程切换开销 死锁与状态同步问题

JS单线程还是多线程?

js是单线程运行的 但使用H5中的 Web Workers可以多线程运行

浏览器运行是单线程还是多线程?

都是多线程

浏览器运行是单进程还是多进程?

有的是单线程
  • 老版火狐firefox(2017年以前)
  • 老版IE
有的是多线程
  • chrome
  • 新版IE

如何查看浏览器是否是多进程运行的呢?

  • 任务管理器-->进程

浏览器内核

1. 支撑浏览器运行的最核心的程序

2. 不同的浏览器可能不一样

Chrome,Safari:webkit firefox:Gecko IE:Trident 360,搜狗等多内浏览器:Trident + webkit

3. 内核由很多模块组成

主线程:

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

分线程:

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

定时器引发的思考

1. 定时器真是定时执行的吗?

定时器并不能保证真正定时执行 一般会延迟一丁点(可以接受),也有可能延迟很长时间(不能接受)

2. 定时器回调函数是在那个线程执行的?

在主线程执行的,js是单线程的

3. 定时器是如何实现的?

事件循环模型(后面讲)

JS是单线程执行的

  1. 如何证明js执行是单线程的?
  2. 为什么js要用单线程模式,而不用多线程模式?
  3. 代码的分类
  4. js引擎执行代码的基本流程
document.querySelector("button").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++) {}
      };

JS是单线程的

1. 如何证明js执行是单线程的?

setTimeout()的对调函数是在主线程执行的 定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行

2. 为什么js要用单线程模式,而不用多线程模式?

JavaSctiptde 的单线程,与它的用途有关 作为浏览器脚本语言,JavaSctipt的主要用途是与用户互动,以及操作DOM 这决定了它只能是单线程,否则会带来很复杂的同步问题

3. 代码分类:

初始化代码 回调函数

4. js引擎执行代码:包含一些特别的代码

先执行初始化代码:包含一些特别的代码

  • 设置定时器
  • 绑定监听
  • 发送ajax请求 后面在某个时刻才会执行回调函数代码

事件循环模型

1. 所有代码分类

初始化执行代码(同步代码):包含绑定dom事件监听,设置定时器,发送ajax请求的代码 回调执行代码(异步代码):处理回调逻辑

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

初始化代码===>回调代码

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

事件管理模块 回调队列

4. 模型的运转流程

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

插入:浏览器的时间虚循环(轮询)模型:

模型原理图

image.png

相关重要概念

  1. 执行栈

execution stack 所有代码都是此空间中执行的

  1. 浏览器内核

browser core js引擎块(在主线程处理) 其他模块(在主/分线程处理)

  1. 任务队列

task queue

  1. 消息队列

message queue

  1. 时间队列

event queue

  1. 事件轮询

event loop 从任务队列中循环取出回调函数放入执行栈中处理(一个接一个)

  1. 事件驱动模型

event-driven interaction model

  1. 请求响应模型

request-response model

Web Workers_测试

1. H5规范提供了js分线程的实现,取名为:Web Workers

2. 相关API

Worker:构造函数,加载分线程执行的js文件 Worker.prototype.onmessage:用于接受另一个线程的回调函数 Worker.prototype.postMessage:向另一个线程发送消息

3. 不足

worker内代码不能操作DOM(更新UI) 不能跨域加载JS 不是每个浏览器都支持这个新特性

var input = document.querySelector("input");
      document.querySelector("button").addEventListener("click", function () {
        var number = input.value;
        function fibonacci(n) {
          // 1 1 2 3 5 8 13 21 34 55 89   f(n) = f(n-1)+f(n-2)
          return n <= 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2); // 递归调用
        }
        console.log(fibonacci(number));
      });

插入H5 Web Workers(多线程)

介绍

Web Workers 是HTML5提供的一个javascript多线程解决方案 我们可以将一些大计算量的代码交由web Worker运行而不冻结用户界面 但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质

使用

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

图解

image.png

应用练习

直接在主线程

var fibonacci =function(n) {
    return n <2 ? n : fibonacci(n -1) + fibonacci(n -2);
};
console.log(fibonacci(48));

使用Worker在分线程

  • 主线程
var worker = new Worker('worker2.js');
worker.addEventListener('message', function (event) {
    var timer2 = new Date().getTime();
    console.log('结果:' + event.data, '时间:' + timer2, '用时:' + ( timer2 - timer ));
}, false);

var timer = new Date().getTime();
console.log('开始计算: ', '时间:' + timer);
setTimeout(function () {
    console.log('定时器函数在计算数列时执行了', '时间:' + new Date().getTime());
}, 1000);

worker.postMessage(40);
console.log('我在计算数列的时候执行了', '时间:' + new Date().getTime());
  • 分线程
var fibonacci =function(n) {
    return n <2 ? n : fibonacci(n -1) + fibonacci(n -2);
};

var onmessage = function(event) {
    var n = parseInt(event.data, 10);
    postMessage(fibonacci(n));
};

不足

  1. 不能跨域加载JS
  2. worker内代码不能访问DOM(更新UI)
  3. 不是每个浏览器都支持这个新特性