JS是门单线程语言
多线程语言
像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。
在处理任务队列中的任务的时候 还有一个点
- 若有微任务,则优先将本轮所有微任务的执行完成,全部结束后 再执行本轮的宏任务
浏览器端的异步实现(事件循环)
以 Chrome 为例,浏览器不仅有多个线程,还有多个进程,如渲染进程、GPU 进程和插件进程等、甚至每个 tab 标签页都是一个独立的渲染进程(所以一个 tab 异常崩溃后,其他 tab 基本不会被影响)。
作为前端开发者,主要重点关注其渲染进程,渲染进程下包含了 JS 引擎线程、HTTP 请求线程和定时器线程等,这些线程为 JS 在浏览器中完成异步任务提供了基础。
JS 是单线程的,也就是同一个时刻只能做一件事情,那么思考:为什么浏览器可以同时执行异步任务呢?
可千万不要搞混了 浏览器本身是多线程的,单线程的只是你的js代码语言本身,
当 JS 需要执行异步任务时,浏览器会另外启动一个线程去执行该任务。
也就是说,“JS 是单线程的”指的是执行 JS 代码的线程只有一个,是浏览器提供的 JS 引擎线程(主线程)。
浏览器中还有定时器线程和 HTTP 请求线程等,这些线程主要不是来跑 JS 代码的。
比如主线程中需要发一个 AJAX 请求,就把这个任务交给另一个浏览器线程(HTTP 请求线程)去真正发送请求,待请求回来了,再将 callback 里需要执行的 JS 回调交给 JS 引擎线程去执行。
即浏览器才是真正执行发送请求这个任务的角色,而 JS 只是负责执行最后的回调处理。
所以这里的异步不是 JS 自身实现的,其实是浏览器为其提供的能力。