js的单线程与异步编程

文章目录

          • javascript是单线程的
          • 浏览器内核是多线程的
          • 浏览器内核里的线程
            • 定时器线程
            • 事件触发线程
            • 异步http请求线程
            • javascript引擎线程
            • GUI线程
          • 事件循环
          • javascript异步编程
            • 回调函数
            • 事件监听
            • 发布订阅
            • Promise
            • async/await
          • 参考文章

javascript是单线程的

javascript可以操作DOM,所以javascript是单线程的
为啥?
试想下,如果javascript是多线程的,就比如现在有两个线程,其中一个是给DOM节点添加内容,另一个是删除这个DOM节点,这时浏览器应该听谁的。为了避免这类复杂的同步问题,javascript就被设计成单线程的了。
Web Worker怎么说?
虽然允许使用Web Worker创建子线程,但子线程完全受控于主线程,且子线程不能操作DOM,所以Web Worker并没有改变javascript是单线程的这一本质。

浏览器内核是多线程的

javascript是单线程的就意味着, 只有等待上一个任务执行完,下一个任务才会开始执行。
就像医院排队候诊一样,如果因为病情复杂需要医生花费更多的时间去分析诊断比如,任务计算量大,不得不让大家多等会儿,可以理解。但是,轮到一位女士时,她却说“哎呀呀,我得回家取趟病例先,再等我two hours”。让大家空等?当然不会,医生会让这位“麻烦女士”先回家取病例,等她取回病例了,她必须在“等候区”等待,直到医生将之前排队的病人全部诊断完毕,空闲下来了,才轮到这位“麻烦女士”。
js的单线程与异步编程_第1张图片
这个"等候区"就是任务队列任务队列里有什么?那我们就得了解下浏览器内核里有啥线程。

浏览器内核里的线程
定时器线程

setTimeoutsetInterval不是由js引擎计时,由浏览器内核的Timer模块处理。
setTimeoutsetInterval所在的线程就是定时器线程。
当计时完成,回调函数就会进入任务队列

事件触发线程

onclickonmouseover等这些事件也不是js引擎的,由浏览器内核的DOM binding模块处理。
当事件触发时,事件处理程序会进入任务队列

异步http请求线程

Ajax也不是js引擎的,由浏览器内核的Network模块处理。网络请求返回后,对应的回调函数也会进入任务队列

javascript引擎线程

javascript引擎线程就是javascript线程主线程,用来执行javascript代码。
主线程空闲后,才会执行任务队列中的任务。

GUI线程

负责渲染页面,包括解析HTML、CSS,构建DOM树、Render树,布局、绘制。
页面重绘或回流,就会运行这个线程。
你肯定听说过,"script标签的加载和解析会阻塞DOM渲染"或者遇到过类似下面的问题。
js的单线程与异步编程_第2张图片
script标签的加载和解析”,就是执行js代码,即运行javascript引擎线程
“DOM渲染”,就是运行GUI线程
是的,GUI线程javascript引擎线程彼此互斥的,有你没我,有我没你。
javascript引擎线程运行时,GUI线程是冻结的,只有javascript引擎线程空闲时,GUI线程才会运行。

事件循环
  • 同步任务

所有的同步任务都在主线程javascript引擎线程上执行,只有上一个任务执行完毕,下一个任务才会开始执行。

  • 异步任务

异步任务经对应的异步线程处理后进入任务队列。比如,setTimeout定时器线程处理后,其回调函数将被放入任务队列
js的单线程与异步编程_第3张图片
所有同步任务都在主线程上执行,因此形成一个执行栈

  1. 主线程在运行的过程中,遇异步任务会将其交给对应的异步线程。经异步线程处理后异步任务会被放入任务队列
  2. 主线程执行完所有同步任务,空闲时,会从任务队列中读取异步任务,此时,异步任务将结束等待状态进入执行栈,开始在主线程上执行。
    js的单线程与异步编程_第4张图片
    1、2重复,就是事件循环

举个简单的例子吧。

        setTimeout(bless,0);
        function sayHi(){
            console.log("hello world");
        }
        function bless(){
            console.log("have a nice day");
        }
        sayHi();
        console.log("nice to meet you");
        console.log("nice to meet you too");
        console.log("how are you");
        console.log("I'm fine");
        console.log("thank you");
        console.log("and you");    

这里,bless就是一个异步任务sayHi和后面一群console.log就是同步任务,所以"have a nice day"会在最后输出。
js的单线程与异步编程_第5张图片

javascript异步编程
回调函数
事件监听
发布订阅
Promise
async/await
参考文章

JS 事件循环机制
浅谈浏览器多进程与JS线程
与JavaScript异步实现密切相关的浏览器内核线程

你可能感兴趣的:(javascript)