什么是进程、线程
进程是一个工厂,工厂有它的独立资源 - 工厂之间相互独立 - 线程是工厂中的工人,多个工人协作完成任务 - 工厂内有一个或多个工人 - 工人之间共享空间
工厂的资源 -> 系统分配的内存(独立的一块内存) - 工厂之间的相互独立 -> 进程之间相互独立 - 多个工人协作完成任务 -> 多个线程在进程中协作完成任务 - 工厂内有一个或多个工人 -> 一个进程由一个或多个线程组成 - 工人之间共享空间 -> 同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)
浏览器
浏览器是多进程的;
浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu、内存);
每打开一个Tab页,就相当于创建了一个独立的浏览器进程;
之前说了浏览器是多进程,当我们每次打开一个tab页面时,就是由于有了以下这些进程浏览器才能把丰富的内容给我们展示出来,
浏览器都有哪些主要进程:
1.Browser进程:浏览器的主进程(负责协调、主控),只有一个。作用有: 负责浏览器界面显示,与用户交互。如前进,后退等; 负责各个页面的管理,创建和销毁其他进程; 将Renderer进程得到的内存中的Bitmap,绘制到用户界面上; 网络资源的管理,下载等;
2.第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
3.GPU进程:最多一个,用于3D绘制等
4.浏览器渲染进程(浏览器内核)(Renderer进程,内部是多线程的):默认每个Tab页面一个进程,互不影响。 我们平时所说的浏览器内核也就是指渲染进程,不同浏览器内核不一样例如: IE:Trident -ms- 火狐:Gecko -moz- Safari/Chrome:Webkit -webkit- Opera:貌似也用谷歌内核了 (早期用Presto现在已经废弃了) -o-
————————————————————————————————————————————————————————
开始讲重点
这里主要讲第4点,渲染进程也叫做Renderer进程(浏览器的渲染进程是多线程的),以上的内容介绍也是为了讲渲染进程来做铺垫方便去理解。
渲染进程有以下多线程:
1.GUI渲染线程 (解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等)
2.JS引擎线程,也就是主线程 (为js代码运行提供一个环境,例如v8引擎,浏览器无论什么时候都只有一个JS线程在运行JS程序)
这里插播介绍一下GUI渲染线程和JS引擎线程的关系,它们两是互斥的,其中一个执行另一个就不能执行,我们都知道网页代码是从上到下执行, 如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞或者GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
3.事件触发线程 (浏览器跑js,忙不过来很多事情都要记得去做,需要一个秘书,等JS引擎线程不忙时秘书在会去提醒还有什么要做的,这里的事件触发线程就相当于秘书的职能,例如:如鼠标点击、AJAX异步、setTimeOut是由事件触发线程负责,等JS引擎线程不忙才会去执行这些事情)
4.定时触发器线程 (执行setInternal与setTimeout是该线程负责,总不能给JS引擎线程来做吧,难道要等setInternal与setTimeout执行完成后才接着去执行其他js代码吗,这样会阻塞。也可以理解为又一个秘书,提醒JS引擎线程不忙时去执行这些事情)
5.异步http请求线程(又一个秘书,提醒JS引擎线程不忙时去回调)
总结:GUI渲染线程和JS引擎线程不能同时执行,其中一个执行另一个就处于等待状态,等对方闲置时才能去执行,至于谁先谁后要遵循代码从上到下、左到右执行。由于很多业务逻辑都需要js去判断,加上浏览器只给了JS引擎线程一个人去完成能力有限就于是分配了3个秘书给他,负责提醒JS引擎线程不忙时要去完成,至始至终JS引擎线程都是一个人去完成的。
JS引擎线程实在是在忙了怎么办?
在html5中于是就请了WebWorker,浏览器允许渲染进程为自己申请一个子线程来帮JS引擎线程的忙,但最终的结果还是要返回给JS引擎线程。JS引擎线程始终还是改变不了单线程的命运。
新的WebWorker线程要和JS引擎线程进行数据通讯就要使用postMessage 。以下是使用postMessage相关文章。
数据跨页面通讯
单个页面就是一个render进程,WebWorker也只是但个页面中render进程下的新线程,不能跨进程共享。
SharedWorker是浏览器所有页面共享的,可以为多个Render进程共享使用。
Promise和setTimeout执行顺序
console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0); Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); console.log('script end'); 结果 script start script end promise1 promise2 setTimeout
总结:主线程上的js先执行完成后就立马执行Promise在之后是setTimeout/setInterval
主线程>Promise>setTimeout/setInterval
为什么JavaScript不能有多个线程呢?
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
相关文章:
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
http://www.dailichun.com/2018/01/21/js_singlethread_eventloop.html