一、进程与线程

1. 进程:

程序的一次执行, 它占有一片独有的内存空间  ---- 可以通过windows任务管理器查看进程;

2. 线程:

是进程内的一个独立执行单元;是程序执行的一个完整流程;CPU的基本调度单位;

3. 进程与线程的关系:

  * 一个进程中一般至少有一个运行的线程: 主线程 -- 进程启动后自动创建;

  * 一个进程中也可以同时运行多个线程, 我们会说程序是多线程运行的;

  * 一个进程内的数据可以供其中的多个线程直接共享;

  * 多个进程之间的数据是不能直接共享的

4. 浏览器运行是单进程还是多进程?

  • 有的是单进程
  • firefox
  • 有的是多进程
  • chrome

5. 如何查看浏览器是否是多进程运行的呢?

任务管理器==>进程

6. 浏览器运行是单线程还是多线程?

都是多线程运行的

二、单线程 

1、什么是单线程

JavaScript语言的一大特点就是单线程,也就是说同一时间只能做一件事。

//栗子🌰 console.log(1)console.log(2)console.log(3)//输出顺序 1 2 3

2. JavaScript为什么是单线程

  • 首先是历史原因,在创建 javascript 这门语言时,多进程、多线程的架构并不流行,硬件支持并不好。
  • 其次是因为多线程的复杂性,多线程操作需要加锁,编码的复杂性会增高。
  • 最后与它的用途有关,作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM,如果同时操作 DOM ,在多线程不加锁的情况下,最终会导致 DOM 渲染的结果不可预期。

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。 

三、同步与异步

1、JS的 同步任务/异步任务

同步任务: 

主线程上排队执行的任务,只有一个任务执行完毕,才能执行一个任务;

所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

 异步任务:主线程外执行的任务;在主线程之外还存在一个“任务队列”(task queue),当异步任务执行完成后会以回调函数的方式放入任务队列中等待,等主线程空闲时,主线程就会去事件队列中取出等待的回调函数放入主线程中进行执行。这个过程反复执行就形成了js的事件循环机制(Event Loop)。

//栗子🌰 
// 同步
console.log(1)
// 异步
setTimeout(()=>{
    console.log(2)
},100)
// 同步
console.log(3)
//输出顺序 1 3 2

2、 JavaScript为什么需要异步

如果在JS代码执行过程中,某段代码执行过久,后面的代码迟迟不能执行,产生阻塞(即卡死),会影响用户体验。

3、JavaScript怎么实现异步 

1)执行栈与任务队列 

其实上面我们已经提到了,JS实现异步时通过 事件循环

我们先理解几个概念:

  • JS任务 分为同步任务(synchronous)和异步任务(asynchronous)
  • 同步任务都在 JS引擎线程(主线程) 上执行,形成一个执行栈(call stack)
  • 事件触发线程 管理一个 任务队列(Task Queue)
  • 异步任务 触发条件达成,将 回调事件 放到任务队列(Task Queue)中
  • 执行栈中所有同步任务执行完毕,此时JS引擎线程空闲,系统会读取任务队列,将可运行的异步任务回调事件添加到执行栈中,开始执行

 当一个JS文件第一次执行的时候,js引擎会 解析这段代码,并将其中的同步代码 按照执行顺序加入执行栈中,然后从头开始执行。如果当前执行的是一个方法,那么js会向执行栈中添加这个方法的执行环境,然后进入这个执行环境继续执行其中的代码。当这个执行环境中的代码 执行完毕并返回结果后,js会退出这个执行环境并把这个执行环境销毁,回到上一个方法的执行环境。这个过程反复进行,直到执行栈中的代码全部执行完毕。

栗子 🌰

//(1)
console.log(1)
//(2)
setTimeout(()=>{
    console.log(2)
},100)
//(3)
console.log(3)

1.先解析整段代码,按照顺序加入到执行栈中,从头开始执行

2.先执行(1),是同步的,所以直接打印 1

3.执行(2),发现是 setTimeout,于是调用浏览器的方法(webApi)执行,在 100ms后将 console.log(2) 加入到任务队列

4.执行(3),同步的,直接打印 3

5.执行栈已经清空了,现在检查任务队列,(执行太快的话可能此时任务队列还是空的,没到100ms,还没有将(2)的打印加到任务队列,于是不停的检测,直到队列中有任务),发现有 console.log(2),于是添加到执行栈,执行console.log(2),同步代码,直接打印 2 (如果这里是异步任务,同样会再走一遍循环:-->任务队列->执行栈)

所以结果是 1 3 2;

注意:setTimeout/Promise等我们称之为任务源。而进入任务队列的是他们指定的回调;

2)宏任务(macro task)与微任务(micro task)

 上面的循环只是一个宏观的表述,实际上异步任务之间也是有不同的,分为 宏任务(macro task) 与 微任务(micro task),最新的标准中,他们被称为 task与 jobs

  • 宏任务有哪些:script(整体代码), setTimeout, setInterval, setImmediate,I/O, UI rendering(渲染)
  • 微任务有哪些:process.nextTick, Promise, Object.observe(已废弃), MutationObserver(html5新特性)

下面我们再详细讲解一下执行过程:

 执行栈在执行的时候,会把宏任务放在一个宏任务的任务队列,把微任务放在一个微任务的任务队列,在当前执行栈为空的时候,主线程会 查看微任务队列是否有事件存在。如果微任务队列不存在,那么会去宏任务队列中 取出一个任务 加入当前执行栈;如果微任务队列存在,则会依次执行微任务队列中的所有任务,直到微任务队列为空(同样,是吧队列中的事件加到执行栈执行),然后去宏任务队列中取出最前面的一个事件加入当前执行栈...如此反复,进入循环。

注意:

  • 宏任务和微任务的任务队列都可以有多个
  • 当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。
  • 不同的运行环境 循环策略可能有不同,这里探讨chrome、node环境

 栗子 🌰 

//(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

下面分析一下执行过程:

1.全部代码在解析后加入执行栈

2.执行(1),宏任务,调用webapi setTimeout,这个方法会在100ms后将回调函数放入宏任务的任务队列

3.执行(2),同(1),但是会比(1)稍后一点

4.执行(3),同步执行new Promise,然后执行(4),直接打印 3 ,然后resolve(4),然后.then(),把(5)放入微任务的任务队列

5.执行(6),同上,先打印 5 ,再执行resolve(6),然后.then()里面的内容(8)加入到微任务的任务队列

6.执行(9),同步代码,直接打印 7

7.执行(10),同(1)和(2),只是时间更短,会在 50ms 后将回调 console.log(8) 加入宏任务的任务队列

8.现在执行栈清空了,开始检查微任务队列,发现(5),加入到执行栈执行,是同步代码,直接打印 4

9.任务队列又执行完了,又检查微任务队列,发现(8),打印 6

10.任务队列又执行完了,检查微任务队列,没有任务,再检查宏任务队列,此时如果超过了50ms的话,会发现 console.log(8) 在宏任务队列中,于是执行 打印 8

11.依次打印 1 2

:因为渲染也是宏任务,需要在一次执行栈执行完后才会执行渲染,所以如果执行栈中同时有几个同步的改变同一个样式的代码,在渲染时只会渲染最后一个。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注Devmax的更多内容!      

JavaScript的三座大山之单线程和异步的更多相关文章

  1. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  2. HTML5数字输入仅接受整数的实现代码

    这篇文章主要介绍了HTML5数字输入仅接受整数的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. html5简介_动力节点Java学院整理

    这篇文章主要介绍了html5简介,用于指定构建网页的元素,这些元素中的大多数都用于描述网页内容,有兴趣的可以了解一下

  5. 单线程保存上的iOS7 NSMergeConflict

    在重新排序两行之后,在单线程应用程序上存在简单数据保存问题.我已经设法简化了编码以重现错误,并希望与其他人一起尝试这一点的第二意见.这是一个完整性检查,因为我怀疑iOS7引入的核心数据问题,因为这在iOS6中运行正常.首先,启动一个新的核心数据项目并创建这个模型……现在再次按下第二个测试按钮并弹出.您应该得到类似于此的NSMergeConflict错误…

  6. ios 8 Homescreen webapp,关闭和打开iPad停止javascript

    我有一个适用于iPad的全屏HTML5网络应用程序,并且刚刚安装了IOS8来试用它,它一切正常,直到你关闭并重新启动iPad.一旦web应用程序重新启动javascript就会停止并加载新页面不会重新启动它.在iPad上的Safari中打开同一页面时,关闭和打开iPad会继续按预期工作.其他人注意到了这个或想出了一个解决方案吗?解决方法这似乎是我在iOS8.1.1更新中解决的.

  7. iOS 6 javascript与object.defineProperty的间歇性问题

    当访问使用较新的Object.defineProperty语法定义属性的对象的属性时,有没有其他人注意到新iOS6javascript引擎中的间歇性错误/问题?https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty我正在看到javascript失败的情况,说

  8. ios – 如何使用JSExport导出内部类的方法

    解决方法似乎没有办法将内部类函数导出到javascript.我将内部类移出并创建了独立的类,它起作用了.

  9. 静音iOS推送通知与React Native应用程序在后台

    我有一个ReactNative应用程序,我试图获得一个发送到JavaScript处理程序的静默iOS推送通知.我看到的行为是AppDelegate中的didReceiveRemoteNotification函数被调用,但是我的JavaScript中的处理程序不会被调用,除非应用程序在前台,或者最近才被关闭.我很困惑的事情显然是应用程序正在被唤醒,并且它的didReceiveRemoteNotifi

  10. ios – 内存泄漏与UIWebView和Javascript

    清楚地包含一个Javascript文件到我的HTML是使UIWebView泄漏内存.当我重复使用相同的UIWebView对象时,或者每当我有内容实例化一个新的漏洞时,会出现泄漏的事实,导致我认为必须有一些JavaScript文件被loadHTMLString处理,导致泄漏.有人知道如何解决这个问题吗?

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部