本篇文章给大家带来了关于JavaScript中单线程和异步的相关知识,希望对大家有帮助。
写这篇文章呢,也是查阅的很多文章,但是大部分写的都很简单,而且概念性的东西都很模糊,于是我就找了一些课程听了一下,做了一些笔记,在这我就简单总结一下,方便以后复习~
1. 进程:程序的一次执行, 它占有一片独有的内存空间 ---- 可以通过windows任务管理器查看进程;
2. 线程: 是进程内的一个独立执行单元;是程序执行的一个完整流程;CPU的基本调度单位;
3. 进程与线程的关系:
* 一个进程中一般至少有一个运行的线程: 主线程 -- 进程启动后自动创建;
* 一个进程中也可以同时运行多个线程, 我们会说程序是多线程运行的;
* 一个进程内的数据可以供其中的多个线程直接共享;
* 多个进程之间的数据是不能直接共享的
4. 浏览器运行是单进程还是多进程?
* 有的是单进程
* firefox
* 有的是多进程
* chrome
5. 如何查看浏览器是否是多进程运行的呢?
* 任务管理器==>进程
6. 浏览器运行是单线程还是多线程?
* 都是多线程运行的
JavaScript语言的一大特点就是单线程,也就是说同一时间只能做一件事。
//栗子 console.log(1) console.log(2) console.log(3) //输出顺序 1 2 3
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
同步任务: 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
异步任务:在主线程外执行的任务;在主线程之外还存在一个“任务队列”(task queue),当异步任务执行完成后会以回调函数的方式放入任务队列中等待,等主线程空闲时,主线程就会去事件队列中取出等待的回调函数放入主线程中进行执行。这个过程反复执行就形成了js的事件循环机制(Event Loop)。
//栗子 // 同步 console.log(1) // 异步 setTimeout(()=>{ console.log(2) },100) // 同步 console.log(3) //输出顺序 1 3 2
如果在JS代码执行过程中,某段代码执行过久,后面的代码迟迟不能执行,产生阻塞(即卡死),会影响用户体验。
其实上面我们已经提到了,JS实现异步时通过 事件循环;
我们先理解几个概念:
当一个JS文件第一次执行的时候,js引擎会 解析这段代码,并将其中的同步代码 按照执行顺序加入执行栈中,然后从头开始执行。如果当前执行的是一个方法,那么js会向执行栈中添加这个方法的执行环境,然后进入这个执行环境继续执行其中的代码。当这个执行环境中的代码 执行完毕并返回结果后,js会退出这个执行环境并把这个执行环境销毁,回到上一个方法的执行环境。这个过程反复进行,直到执行栈中的代码全部执行完毕。
栗子
//(1) console.log(1) //(2) setTimeout(()=>{ console.log(2) },100) //(3) console.log(3)
所以结果是 1 3 2;
注意:setTimeout/Promise等我们称之为任务源。而进入任务队列的是他们指定的回调;
上面的循环只是一个宏观的表述,实际上异步任务之间也是有不同的,分为 宏任务(macro task) 与 微任务(micro task),最新的标准中,他们被称为 task与 jobs
下面我们再详细讲解一下执行过程:
执行栈在执行的时候,会把宏任务放在一个宏任务的任务队列,把微任务放在一个微任务的任务队列,在当前执行栈为空的时候,主线程会 查看微任务队列是否有事件存在。如果微任务队列不存在,那么会去宏任务队列中 取出一个任务 加入当前执行栈;如果微任务队列存在,则会依次执行微任务队列中的所有任务,直到微任务队列为空(同样,是吧队列中的事件加到执行栈执行),然后去宏任务队列中取出最前面的一个事件加入当前执行栈...如此反复,进入循环。
注意:
栗子
//(1) setTimeout(()=>{ console.log(1) // 宏任务 },100) //(2) setTimeout(()=>{ console.log(2) // 宏任务 },100) //(3) new Promise(function(resolve,reject){ //(4) console.log(3) // 直接打印 resolve(4) }).then(function(val){ //(5) console.log(val); // 微任务 }) //(6) new Promise(function(resolve,reject){ //(7) console.log(5) // 直接打印 resolve(6) }).then(function(val){ //(8) console.log(val); // 微任务 }) //(9) console.log(7) // 直接打印 //(10) setTimeout(()=>{ console.log(8) // 宏任务,单比(1)(2)宏任务早 },50)
上面的代码在node和chrome环境的正确打印顺序是 3 5 7 4 6 8 1 2
下面分析一下执行过程:
注:因为渲染也是宏任务,需要在一次执行栈执行完后才会执行渲染,所以如果执行栈中同时有几个同步的改变同一个样式的代码,在渲染时只会渲染最后一个。
相关推荐:javascript学习教程
以上是经典技巧之JavaScript的单线程和异步的详细内容。更多信息请关注PHP中文网其他相关文章!