JavaScript单线程机制与setTimeout执行原理的介绍(附代码)
本篇文章给大家带来的内容是关于JavaScript单线程机制与setTimeout执行原理的介绍(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
Javascript 引擎单线程机制
首先明确,JavaScript引擎是单线程机制。
JavaScript 是单线程执行的,无法同时执行多段代码。当某一段代码正在执行的时候,所有后续的任务都必须等待,形成一个任务队列。一旦当前任务执行完毕,再从队列中取出下一个任务,这也常被称为 “阻塞式执行”。
可以理解为:只有在JS线程中没有任何同步代码要执行的前提下才会执行异步代码
所以一次鼠标点击,或是计时器到达时间点,或是 Ajax 请求完成触发了回调函数,这些事件处理程序或回调函数都不会立即运行,而是立即排队,一旦线程有空闲就 执行。假如当前 JavaScript 线程正在执行一段很耗时的代码,此时发生了一次鼠标点击,那么事件处理程序就被阻塞,用户也无法立即看到反馈,事件处理程序会被放入任务队列,直到前面的代码结束以后才会开始执行。如果代码中设定了一个 setTimeout,那么浏览器便会在合适的时间,将代码插入任务队列,如果这个时间设为 0,就代表立即插入队列,但不是立即执行,仍然要等待前面代码执行完毕。所以 setTimeout 并不能保证执行的时间,是否及时执行取决于 JavaScript 线程是拥挤还是空闲。浏览器的多线程机制与事件循环(event loop)
首先明确,浏览器的内核是多线程的,它们在内核制控下相互配合以保持同步,一个浏览器至少实现三个常驻线程:
javascript 引擎线程
GUI 渲染线程
浏览器事件触发线程
JavaScript 引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序
javascript 引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。
GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自 JavaScript 引擎当前执行的代码块如 setTimeOut,也可来自浏览器内核的其他线程如鼠标点击、AJAX 异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。(当线程中没有执行任何同步代码的前提下才会执行异步代码)
事件循环(event loop): 是用来管理我们的异步代码的,它会把它们放在一个线程池当中
JavaScript中setTimeout的实现原理
首先明确,setTimeout函数是异步代码,但其实setTimeout并不是真正的异步操作
由于JS线程的工作机制:当线程中没有执行任何同步代码的前提下才会执行异步代码,setTimeout是异步代码,所以setTimeout只能等js空闲才会执行
前面提到过,如果代码中设定了一个 setTimeout,那么浏览器便会在合适的时间,将代码插入任务队列,如果这个时间设为 0,就代表立即插入队列,但不是立即执行,仍然要等待前面代码执行完毕。所以 setTimeout 并不能保证执行的时间,是否及时执行取决于 JavaScript 线程是拥挤还是空闲。
也就是说setTimeout只能保证在指定的时间过后将任务(需要执行的函数)插入队列等候,并不保证这个任务在什么时候执行。执行javascript的线程会在空闲的时候,自行从队列中取出任务然后执行它。javascript 通过这种队列机制,给我们制造一个异步执行的假象。
有时setTimeout中的代码会很快得到执行,我们会感觉这段代码是在异步执行,这是因为 javascript 线程并没有因为什么耗时操作而阻塞,所以可以很快地取出排队队列中的任务然后执行它。
实例分析
在具备了上述理论基础之后,我们对以下几个实例进行分析:
===========================================
var t = true; window.setTimeout(function (){ t = false; },1000); while (t){} alert('end');
运行结果:程序陷入死循环,t = false
得不到执行,因此 alert('end')
不会执行。
解析:
JS是单线程的,所以会先执行 while(t){} 再 alert,但这个循环体是死循环,所以永远不会执行alert。
为什么不执行 setTimeout?是因为JS的工作机制是:当线程中没有执行任何同步代码的前提下才会执行异步代码,setTimeout是异步代码,所以 setTimeout 只能等JS空闲才会执行,但死循环是永远不会空闲的,所以 setTimeout 也永远得不到执行。
===========================================
var start = new Date(); setTimeout(function(){ var end = new Date(); console.log("Time elapsed: ", end - start, "ms"); }, 500); while (new Date - start <= 1000){}
运行结果:"Time elapsed: 1035 ms" (这里的1035不准确 但是一定是大于1000的)
解析:
JS是单线程 setTimeout 异步代码 其回调函数执行必须需等待主线程运行完毕
当while循环因为时间差超过 1000ms 跳出循环后,setTimeout 函数中的回调才得以执行
===========================================
for(var i=0;i<10;i++){ setTimeout(function() { console.log(i); }, 0); }
运行结果:输出10个10
解析:JS单线程 setTimeout 异步代码 任务队列
问:如何修改可以使上述代码输出 0123456789
自执行函数 或 使用ES6中的let关键字
// 自执行函数 形成闭包 记忆其被创建时的环境 for(var i=0;i<10;i++){ setTimeout((function() { console.log(i); })(), 0); }
setTimeout(0)函数的作用
现在我们了解了setTimeout函数执行的原理,那么它有什么作用呢?
setTimeout函数增加了Javascript函数调用的灵活性,为函数执行顺序的调度提供极大便利。
简言之,改变顺序,这正是setTimeout(0)的作用。
使用场景示例:
<input type="text" onkeydown="show(this.value)"> <p></p> <script type="text/javascript"> function show(val) { document.getElementsByTagName('p')[0].innerHTML = val; } </script>
这里绑定了 keydown 事件,意图是当用户在文本框里输入字符时,将输入的内容实时地在
中显示出来。但是实际效果并非如此,可以发现,每按下一个字符时,
中只能显示出之前的内容,无法得到当前的字符。
修改代码:
<input type="text" onkeydown="var self=this; setTimeout(function(){show(self.value)}, 0)"> <p></p> <script type="text/javascript"> function show(val) { document.getElementsByTagName('p')[0].innerHTML = val; } </script>
这段代码使用setTimeout(0)就可以实现需要的效果了。
这里其实涉及2个任务,1个是将键盘输入的字符回写到输入框中,一个是获取文本框的值将其写入p中。第一个是浏览器自身的默认行为,一个是我们自己编写的代码。很显然,必须要先让浏览器将字符回写到文本框,然后我们才能获取其内容写到p中。改变顺序,这正是setTimeout(0)的作用。
其他应用场景:有时候,加载一些广告的时候,我们用setTimeout实现异步,好让广告不会阻塞我们页面的渲染。
setTimeout 和 setInterval 在执行异步代码的时候有着根本的不同
如果一个计时器被阻塞而不能立即执行,它将延迟执行直到下一次可能执行的时间点才被执行(比期望的时间间隔要长些)
如果setInterval回调函数的执行时间将足够长(比指定的时间间隔长),它们将连续执行并且彼此之间没有时间间隔。
本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的JavaScript视频教程栏目!
以上是JavaScript单线程机制与setTimeout执行原理的介绍(附代码)的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

如何使用WebSocket和JavaScript实现在线语音识别系统引言:随着科技的不断发展,语音识别技术已经成为了人工智能领域的重要组成部分。而基于WebSocket和JavaScript实现的在线语音识别系统,具备了低延迟、实时性和跨平台的特点,成为了一种被广泛应用的解决方案。本文将介绍如何使用WebSocket和JavaScript来实现在线语音识别系

WebSocket与JavaScript:实现实时监控系统的关键技术引言:随着互联网技术的快速发展,实时监控系统在各个领域中得到了广泛的应用。而实现实时监控的关键技术之一就是WebSocket与JavaScript的结合使用。本文将介绍WebSocket与JavaScript在实时监控系统中的应用,并给出代码示例,详细解释其实现原理。一、WebSocket技

如何利用JavaScript和WebSocket实现实时在线点餐系统介绍:随着互联网的普及和技术的进步,越来越多的餐厅开始提供在线点餐服务。为了实现实时在线点餐系统,我们可以利用JavaScript和WebSocket技术。WebSocket是一种基于TCP协议的全双工通信协议,可以实现客户端与服务器的实时双向通信。在实时在线点餐系统中,当用户选择菜品并下单

如何使用WebSocket和JavaScript实现在线预约系统在当今数字化的时代,越来越多的业务和服务都需要提供在线预约功能。而实现一个高效、实时的在线预约系统是至关重要的。本文将介绍如何使用WebSocket和JavaScript来实现一个在线预约系统,并提供具体的代码示例。一、什么是WebSocketWebSocket是一种在单个TCP连接上进行全双工

JavaScript和WebSocket:打造高效的实时天气预报系统引言:如今,天气预报的准确性对于日常生活以及决策制定具有重要意义。随着技术的发展,我们可以通过实时获取天气数据来提供更准确可靠的天气预报。在本文中,我们将学习如何使用JavaScript和WebSocket技术,来构建一个高效的实时天气预报系统。本文将通过具体的代码示例来展示实现的过程。We

JavaScript教程:如何获取HTTP状态码,需要具体代码示例前言:在Web开发中,经常会涉及到与服务器进行数据交互的场景。在与服务器进行通信时,我们经常需要获取返回的HTTP状态码来判断操作是否成功,根据不同的状态码来进行相应的处理。本篇文章将教你如何使用JavaScript获取HTTP状态码,并提供一些实用的代码示例。使用XMLHttpRequest

用法:在JavaScript中,insertBefore()方法用于在DOM树中插入一个新的节点。这个方法需要两个参数:要插入的新节点和参考节点(即新节点将要被插入的位置的节点)。

JavaScript中的HTTP状态码获取方法简介:在进行前端开发中,我们常常需要处理与后端接口的交互,而HTTP状态码就是其中非常重要的一部分。了解和获取HTTP状态码有助于我们更好地处理接口返回的数据。本文将介绍使用JavaScript获取HTTP状态码的方法,并提供具体代码示例。一、什么是HTTP状态码HTTP状态码是指当浏览器向服务器发起请求时,服务
