多线程语言

像java、python等 它们都是仅支持同步语言,像读取文件、网络请求这种任务 花费时间很长,它们只能长时间等着。

遇到其他紧急任务,Java 可以再开一个线程去处理。

多线程语言的好处是,在同一时间让 cpu 处理多个事情。

充分的利用cpu多核多线程的资源优势。

程序也会执行的更快!

支持多线程的语言有特别多,比如java、python 等

class RunnableDemo implements Runnable {
private Thread t;
private final String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println("创建 " + threadName );
} public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("运行 " + threadName );
} public void start () {
System.out.println("启动 " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
} public class Main {
// 默认第1个主线程
public static void main(String[] args) {
System.out.println("主线程运行" );
new RunnableDemo( "线程2").start(); // 开启第2个线程(虽然等待3s,但是下边代码会同事执行 不会阻断)
new RunnableDemo( "线程3").start(); // 开启第3个线程
}
}

单线程语言

像类似于 js等语言,由于单线程限制,则不能同时调用cpu的多线程 跑任务,它只能一个时间点只能做一件事情,遇到耗时的任务 这种长时间的空闲等待是不可接受的。

所以js便采取了以下的“异步任务回调通知”模式 来达到类似的效果(关于js异步相关的知识 下边单独讲)

console.log("主程序1结束");
setTimeout(() => {
console.log("异步程序2");
}, 3000); // 虽然需要耗时3s 单并不会阻塞后续代码执行(这里类似于开线程的效果)
console.log('主程序1结束');

事件循环

事件循环是JavaScript实现异步的一种方法,也是JavaScript的执行机制

JS 本身不实现事件循环机制,这是由它的宿主实现的,浏览器中的事件循环主要是由浏览器来实现,而在 NodeJS 中也有自己的事件循环实现。

当一段JS代码执行的时候,首先它是从磁盘被加载到内存(划分一片空间上下文,也叫做执行栈),然后cpu 去执行,

1· JS 引擎会从上到下、从左到右的执行完成所有的同步任务,期间碰到异步任务的时候放到任务队列中。

2. 所有的同步任务执行完毕,主线程会去看看任务队列是否有任务,若有任务则将任务推到主线程执行

3. 执行结束,会再次去看任务队列是否有任务 以此类推 循环往复 每一次循环就是一个事件周期或称为一次 tick。

在处理任务队列中的任务的时候 还有一个点

  1. 若有微任务,则优先将本轮所有微任务的执行完成,全部结束后 再执行本轮的宏任务

浏览器端的异步实现(事件循环)

以 Chrome 为例,浏览器不仅有多个线程,还有多个进程,如渲染进程、GPU 进程和插件进程等、甚至每个 tab 标签页都是一个独立的渲染进程(所以一个 tab 异常崩溃后,其他 tab 基本不会被影响)。

作为前端开发者,主要重点关注其渲染进程,渲染进程下包含了 JS 引擎线程、HTTP 请求线程和定时器线程等,这些线程为 JS 在浏览器中完成异步任务提供了基础。

JS 是单线程的,也就是同一个时刻只能做一件事情,那么思考:为什么浏览器可以同时执行异步任务呢?

可千万不要搞混了 浏览器本身是多线程的,单线程的只是你的js代码语言本身,

当 JS 需要执行异步任务时,浏览器会另外启动一个线程去执行该任务。

也就是说,“JS 是单线程的”指的是执行 JS 代码的线程只有一个,是浏览器提供的 JS 引擎线程(主线程)。

浏览器中还有定时器线程和 HTTP 请求线程等,这些线程主要不是来跑 JS 代码的。

比如主线程中需要发一个 AJAX 请求,就把这个任务交给另一个浏览器线程(HTTP 请求线程)去真正发送请求,待请求回来了,再将 callback 里需要执行的 JS 回调交给 JS 引擎线程去执行。

即浏览器才是真正执行发送请求这个任务的角色,而 JS 只是负责执行最后的回调处理。

所以这里的异步不是 JS 自身实现的,其实是浏览器为其提供的能力。

webworker

比如说 下边一段代码 非常卡 因为运算量大,这就导致弹窗半天才出来 要怎么解决

let sum = 0;
for (let i = 0; i < 200000; i++) {
for (let i = 0; i < 10000; i++) {
sum += Math.random();
}
}
alert("哈哈");

有很多人可能会这样想

const getSum = () => {
return new Promise((reslove) => {
let sum = 0;
for (let i = 0; i < 20000; i++) {
for (let i = 0; i < 10000; i++) {
sum += Math.random();
}
}
reslove(sum)
});
};
getSum().then(res=>{
console.log(res);
})
alert("哈哈");

事实上 这样没用

Promise 是用来管理异步编程的,它本身不是异步的 ,promise是同步代码

走的依然是所有js同步代码都公用的JS 引擎线程

所以就会阻塞下边的js代码。

那就找一个 可以触发浏览器单独线程的代码 使其在另一个线程运行就行了,这样就可以了

setTimeout(() => {
let sum = 0;
for (let i = 0; i < 20000; i++) {
for (let i = 0; i < 10000; i++) {
sum += Math.random();
}
}
});
alert("哈哈");

当然最后 还是搬出我们web worker,他可以不借助任何浏览器提供的线程方案,而是自己单独开一个线程

你每次new Worker都会开启一个新线程

// 主线程 index.js
const worker = new Worker("work.js");
// 线程之间通过postMessage进行通信
worker.postMessage(0); // 向子线程发消息
// 监听线程之间message事件
worker.onmessage = function (e) { // 接受子线程的消息
// 关闭线程
worker.terminate();
// 获取计算结束的时间
console.log("计算结果:", e.data);
console.log(`代码执行了 ${e.timeStamp} 毫秒`);
};
alert("哈哈"); // 子线程 work.js
this.addEventListener("message", (e) => { // 接受主线程的消息
let sum = e;
for (let i = 0; i < 2000; i++) {
for (let i = 0; i < 100; i++) {
sum += Math.random();
}
}
postMessage(sum); // 向主线程发消息
});

web worker总结

这里是web worker的官方文档

WebWorker是HTML5提供的一种浏览器内置的多线程解决方案,就是为js创造多线程的环境。

允许主线程创建webwork线程,将未处理的一些任务分给后者

运行.在js主线程运行的同时,work线程在后台运行,两者互不打扰

等到webwork线程的任务结束后,把结果返回给主线程

web worker的注意点

(1) 同源限制:分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
(2) DOM限制:Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。
(3) 通信联系:Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成
(4) 脚本限制:Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。
(5) 文件限制: Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。

postMessage 传递消息的时候 需要传入的是字符串或可以序列化的对象,否则会出现错误。

小结

虽然js语言本身不能多线程,但是浏览器背后可以做,你的每一个异步,对应就是它在后台帮你多线程做任务。

即便这样 最新的webworker 还是给了你开启线程任务的能力!

JS是门单线程语言的更多相关文章

  1. 探秘JS的异步单线程

    对于通常的developer(特别是那些具备并行计算/多线程背景知识的developer)来讲,js的异步处理着实称得上诡异.而这个诡异从结果上讲,是由js的“单线程”这个特性所导致的. 我曾尝试用“ ...

  2. js为什么是单线程的?10分钟了解js引擎的执行机制

    深入理解JS引擎的执行机制 1.JS为什么是单线程的? 为什么需要异步? 单线程又是如何实现异步的呢? 2.JS中的event loop(1) 3.JS中的event loop(2) 4.说说setT ...

  3. JS(异步与单线程)

    JS(异步与单线程) 题目1.同步和异步的区别是什么,试举例(例子见知识点) 区别: 1.同步会阻塞代码执行,而异步不会 2.alert 是同步,setTimeout 是异步 题目2.关于 setTi ...

  4. 对QT的理解——能在公司里不做Java,不做很偏门的产品,不使用偏门的语言,还有钱挣,要有感恩的心

    我的理解: QT做应用软件可以很强大,界面足够漂亮(最有意思的是QSS,让我刮目相看),应该是足够了.同时QT也提供了源码,不过超级复杂,难以理解,所以还是无法深入底层.另外它提供了一个额外的好处,就 ...

  5. 基于JS的高级脚本语言 Sara

    Sara-基于JS的高级脚本语言 欢迎使用Sara,Sara是一款基于JavaScript的全新的高级脚本语言! Sara不像我们工作室上一款编程语言作品-Ginit一样,他属于更高级的语言 Sara ...

  6. WASM 成为 HTML、CSS 与 JS 之后的第 4 门 Web 语言

    大家都知道,万维网联盟 W3C 认证的 Web 语言有 HTML.CSS 与 JavaScript,而近日联盟正式宣布 WebAssembly 核心规范(WebAssembly Core Specif ...

  7. JS有趣的单线程

    一.JS的执行特点    源于单线程的特性, JS在一段时间内只能执行一部分代码, 那么, 当有多块代码需要执行时, 就需要排队等候了.   二.单线程与异步事件 (1) 什么是异步事件?     异 ...

  8. JS为什么是单线程的?

    JavaScript语言最大的特点就是单线程.它是浏览器的脚本语言.在同一时间只能做一件事.用于操作DOM.如果JS是多线程的,当我在给一个DOM添加内容时,又删除了这个DOM,那么JS该怎么做. 关 ...

  9. [Js]滑动门效果

    描述:鼠标移动到一副图片上,会显示该副图片的全貌,而其他图片会显示概貌 一.没有动画效果的运动 思路: 1.定好每张图片的初始位置(第一张完全显示,234只露出一部分) 2.计算每道门的移动距离(即未 ...

  10. js 滑动门的实现

    原理:滑动门,这里以图片进行实例,首先设定主盒子div的宽度和高度设定,并进行图片初始化位置的设定,然后将图片绑定事件,并设定要达到的效果 html代码: <!DOCTYPE html> ...

随机推荐

  1. Linux C线程读写锁深度解读 | 从原理到实战(附实测数据)

    Linux C线程读写锁深度解读 | 从原理到实战(附实测数据) 读写锁练习:主线程不断写数据,另外两个线程不断读,通过读写锁保证数据读取有效性. 代码实现如下: #include <stdio ...

  2. 使用Python可视化磁场

    引言 随着科学技术的发展,物理学中的很多概念变得越来越复杂,但我们可以利用 Python 这一强大的工具,将一些抽象的物理现象变得更加直观易懂.今天,我们将以"磁场可视化"为主题, ...

  3. Ruby+Selenium+testunit web自动化demo

    1.安装对应库 使用RubyMine新建项目打开终端安装对应库 gem install selenium-webdriver gem install test-unit 如果安装不成功,请切换到国内源 ...

  4. java 实现发送邮件功能

    最近工作项目中需要使用到邮件功能,参考网上的文章,实现了一个基于java的邮件发送功能:直接上代码: 1.依赖 <dependency> <groupId>org.spring ...

  5. this 和super 关键字的区别

    this关键字 (1) 每个类的每个非静态方法(没有被static修饰)都会隐含一个this关键字,它指向调用这个方法的对象:当在方法中使用本类属性时,都会隐含地使用this关键字,当然也可以明确使用 ...

  6. 重磅升级!MCPmarket.cn 开启云托管时代,打造智能体开发的“App Store“ , 一键即可直连MCP工具百宝箱

    [关键词:MCP, MCPmarket, Claude, Cursor, AI Agent, 云托管 MCP, Model Context Protocol, MCP Server 部署, Claud ...

  7. 逻辑与(&)、短路与(&&)、逻辑或(|)、短路或(||)

    目录 逻辑与(&).短路与(&&).逻辑或(|).短路或(||)的区别 逻辑与(&) 短路与(&&) 逻辑或(|) 短路或(||) 逻辑与(&) ...

  8. 【工具】VS Code Counter|除了Gitstats之外的Github一键统计代码行数工具

    需求: 1)被要求统计代码行数: 2)不想打开Linux,懒得下载Windows版本GitStats: 3)打开了Linux但也不记得find命令行怎么用: 4)打开了Linux,装好了Gitstat ...

  9. 【经验】Git|Windows下如何管理和部署多个Git账号的SSH密钥文件

    生成 SSH 密钥 先打开一个git窗口,生成ssh密钥. 如果打开的不是git窗口,而是cmd窗口,则需要先切换到C:\Users\用户名\.ssh目录下. 下面这条指令的your_email和yo ...

  10. DeepSeek+Coze实战:从0到1搭建小红书图文改写智能体(喂饭级教程)

    大家好,我是汤师爷,专注AI智能体分享~ 还在为小红书笔记创作发愁吗? 每天都要绞尽脑汁想文案,看着别人的爆款笔记却不知道如何模仿? 今天,我就教你如何利用AI智能体,轻松实现小红书图文改写,让创作效 ...