JS是门单线程语言

丁少华 / 2023-08-02 / 原文

多线程语言

像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 自身实现的,其实是浏览器为其提供的能力。