一、进程与线程1、进程进程是指程序的一次执行,它占有唯一的内存空间,可以通过windows任务管理器查看(如下图)。同时允许两个或多个进程在同一个计算机系统中并行运行,这就是多进程。比如电脑同时运行微信、QQ、各种浏览器。有的浏览器是单进程运行的,比如firefox和旧版IE,也有的是多进程运行的,比如chrome和新版IE。2、线程有些进程同时做不止一件事情,比如Word,可以同时进行打字、拼写检查、打印等事情。在一个进程内部,如果要同时做多件事情,就需要同时运行多个“子任务”。我们在进程中称这些“子任务”为线程(Thread)。线程是指CPU的基本调度单位,是程序执行的一个完整过程,是一个进程内独立的执行单元。多线程是指在一个进程中,有多个线程同时运行。浏览器运行多线程。例如,使用浏览器同时下载、听歌、看视频。另外,我们要知道JavaScript语言的一大特点就是单线程。为了利用多核CPU的计算能力,HTML5提出了WebWorker标准,允许JavaScript脚本创建多个线程,但子线程完全由主线程控制,不得操作DOM。因此,这个新标准并没有改变JavaScript的单线程特性。因为每个进程至少要做一件事,所以一个进程至少有一个线程。当然像Word这样复杂的进程是可以有多个线程的,多个线程可以同时执行。多线程的执行方式和多进程是一样的。所有线程都短暂交替,似乎在同时执行。当然,真正的多线程同时执行需要多核CPU才有可能。3.进程和线程应用程序必须运行在某个进程的某个线程上。一个进程中至少有一个运行线程:主线程,进程启动后自动创建一个进程。如果多个线程同时运行,则程序是多个线程运行的一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。多个进程之间不能直接共享数据4、单线程和多线程的优缺点?单线程的优点:顺序编程简单易懂单线程的缺点:效率低多线程的优点:可以有效提高CPU性能多线程的利用缺点:产生多线程开销线程间死锁和状态同步问题的切换开销2、浏览器内核浏览器内核是指支持浏览器运行的核心程序。它分为两部分,一。一个是渲染引擎,一个是JS引擎。现在JS引擎相对独立,内核更倾向于说渲染引擎。1.不同的浏览器可能不太一样。Chrome、Safari:webkitfirefox:GeckoIE:Trident360、搜狗等国产浏览器:Trident+webkit2。核心由许多模块组成。HTML、css文件解析模块:负责页面文本解析dom/css模块:负责dom/css在内存中的相关处理布局渲染模块:负责页面布局和效果绘制定时器模块:负责定时器管理网络请求模块:负责服务器请求(常规/Ajax)事件响应模块:负责事件管理3.定时器引起的思考1.定时器真的是定时执行的吗?我们先来看一个例子。定时器会保证200ms后执行吗?document.getElementById('btn').onclick=function(){varstart=Date.now()console.log('开始定时器之前...')setTimeout(function(){console.log('定时器执行',Date.now()-start)},200)console.log('Afterstartingthetimer...')//doalongjobfor(vari=0;i<1000000000;i++){}}实际上,定时器是在625ms之后执行的。定时器不保证真正定时执行,一般会延迟一点点,也有可能延迟很长时间(比如上面的例子)2.定时器回调函数是在单独的线程中执行的吗?定时器回调函数在主线程中执行,具体实现在下面介绍。四、浏览器的事件循环(轮询)模型1、为什么JavaScript是单线程的JavaScript语言的一大特点就是单线程,即同一时间只能做一件事情。那么,为什么JavaScript不能有多线程呢?这样可以提高效率啊。JavaScript的单线程与它的使用有关。作为一种浏览器脚本语言,JavaScript的主要目的是与用户交互和操作DOM。这就决定了它只能是单线程的,否则会带来非常复杂的同步问题。例如,假设JavaScript同时有两个线程,一个线程向某个DOM节点添加内容,另一个线程删除这个节点,那么浏览器应该以哪个线程为基础呢?因此,为了避免复杂性,JavaScript从一开始就是单线程的,这已经成为这门语言的核心特征,以后也不会改变。为了利用多核CPU的计算能力,HTML5提出了WebWorker标准,允许JavaScript脚本创建多个线程,但子线程完全由主线程控制,不得操作DOM。因此,这个新标准并没有改变JavaScript的单线程特性。2.EventLoopJavaScript中的所有任务可以分为两种,一种是同步任务,一种是异步任务(比如各种浏览器事件,定时器和Ajax等)。同步任务是指在主线程上排队等待执行的任务,只有上一个任务执行完才能执行下一个任务;异步任务是指不进入主线程而是进入“任务队列”(taskqueue)的任务,只有当“任务队列”通知主线程有异步任务可以执行时,任务才会进入执行的主线程。具体来说,异步执行的运行机制如下。(同步执行也是如此,因为它可以看作是异步执行,没有异步任务。)(1)所有同步任务都在主线程上执行,形成一个执行上下文栈。(2)除了主线程之外,还有一个“任务队列”。只要异步任务有运行结果,就会在“任务队列”中放入一个事件。(3)一旦“执行栈”中的所有同步任务都执行完毕,系统就会去读取“任务队列”,看看里面有什么事件。那些对应的异步任务结束等待状态,进入执行栈,开始执行。(4)主线程不断重复上面的第三步。主线程从“任务队列”中读取事件。这个过程是循环的,所以整个运行机制也称为事件循环(eventloop)。下面的例子很好地说明了事件循环:setTimeout(function(){console.log('timeout2222')alert('22222222')},2000)setTimeout(function(){console.log('timeout1111')alert('1111111')},1000)setTimeout(function(){console.log('timeout()00000')},0)//当指定值小于4毫秒时,增加到4ms(4ms由HTML5标准指定,对于2010和更早的浏览器是10ms)functionfn(){console.log('fn()')}fn()console.log('beforealert()')alert('------')//暂停当前主线程的执行,同时暂停计时。点击确定后恢复程序执行并计时console.log('afteralert()')有两点我们需要注意:定时器零延迟(setTimeout(func,0))并不代表回调函数是立即执行。至少4ms,回调函数才会执行。这取决于主线程当前是否空闲以及“任务队列”中在其前面等待的任务。只有到了指定的时间,定时器才会将相应的回调函数插入到“任务队列”中。然后在达到其指定参数时)。当Stack栈(JavaScript主线程)为空时,会读取Queue队列(任务队列)的第一个任务(组长),最后执行。五、H5WebWorkers(多线程)1.WebWorkers的作用上面说了JavaScript是单线程的。当页面加载一个包含复杂计算的js文件时,用户界面可能会短暂“卡住”,无法进行其他操作。例如下面的例子:
