First we need to know that <span style="font-size: 14px;">JavaScript</span>
is a Single-threaded interpreted language. This means that we can only execute one command at the same time. The reason why it is a single-threaded language has to do with its purpose.
JavaScript was originally designed to enhance the interaction between the browser and the user, especially the interaction with the form. Later Ajax technology was also invented to make the interaction with the form more humane. Because JavaScript is an interpreted language, and the interpreter is embedded in the browser, this interpreter is single-threaded.
The reason why it is not designed to be multi-threaded is because multi-threading can easily cause deadlocks or resource conflicts when rendering web pages. But the browser itself is multi-threaded. For example, it interprets and runs JavaScript while loading network resources.
Why doesn't JavaScript support multithreading?
Single thread means that if you want to run a lot of commands, then these commands need to be sorted. Under normal circumstances, these commands are executed in order from top to bottom ( Because the interpreter starts at the top of the file). For example, the following code is executed in order.
<span style="font-size: 14px;">console.log("1");<br>console.log("2");<br>console.log("3");<br>//1<br>//2<br>//3<br></span>
But we also know that there is asynchronous programming in JavaScript, such as Ajax, setTimeout, setInterval or Promise, async, await in ES6.
The execution of a command in the computer means that it is using resources such as the CPU at this time, so there are many commands that want to obtain CPU resources, and the CPU executes commands It also takes time to calculate and obtain the result, so there is the concept of synchronous and asynchronous.
Synchronization means that when a CPU request is issued, the CPU request will not return until the result is obtained. But once the call returns, you get the return value.
Asynchronous means that after the CPU request is issued, the call returns directly, so no result is returned. After the operation is completed, a series of means are needed to obtain the return value
At this time, the concepts of process and thread must be introduced.
Concept: A process is a process with certain The dynamic execution process of a program with independent functions on a data set is an independent unit for resource allocation and scheduling by the operating system, and is the carrier for application running.
Since the process uses the CPU in turns, there is process switching, but due to the current program They are all relatively large, and the switching overhead is very high, which will waste CPU resources, so threads were invented to decompose a large process into multiple threads for joint execution.
#The process is the smallest unit for the operating system to allocate resources, and the thread is the smallest unit for program execution.
A process consists of one or more threads. Threads are different execution routes of code in a process;
Processes are independent of each other, but threads in the same process share the program's memory space (including code segments, data sets, heaps, etc.) and some process-level resources (such as open files and signals) ).
# Scheduling and switching: Thread context switching is much faster than process context switching.
If I were Naruto, I would like to eat a lot of ramen. If I eat it alone If there are 10 bowls, then I will finish eating ramen in one process and one thread.
But if I use 9 clones to eat 10 bowls of ramen with me, then I am a process using 9 threads to complete the task of eating ramen.
The multi-process means that while the celebrity is eating ramen in Ichiraku Ramen, the lustful immortal is peeking at the girl taking a bath~~. The lustful immortal is a single process and single thread to take a peek!
The kernel of the browser is multi-threaded. Under the control of the kernel, each thread cooperates with each other to maintain synchronization. The browser usually consists of the following threads:
GUI rendering thread
JavaScript引擎线程
事件触发线程
异步http请求线程
EventLoop轮询的处理线程
这些线程的作用:
UI线程用于渲染页面
js线程用于执行js任务
浏览器事件触发线程用于控制交互,响应用户
http线程用于处理请求,ajax是委托给浏览器新开一个http线程
EventLoop处理线程用于轮询消息队列
因为JavaScript是单线程的,而浏览器是多线程的,所以为了执行不同的同步异步的代码,JavaScript运行的环境采用里事件循环和消息队列来达到目的。
每个线程的任务执行顺序都是FIFO(先进先出)
在JavaScript运行的环境中,有一个负责程序本身的运行,作为主线程;另一个负责主线程与其他线程的通信,被称为<span style="font-size: 14px;">Event Loop 线程</span>
。
每当主线程遇到异步的任务,把他们移入到<span style="font-size: 14px;">Event Loop 线程</span>
,然后主线程继续运行,等到主线程完全运行完之后,再去<span style="font-size: 14px;">Event Loop 线程</span>
拿结果。
而每个异步任务都包含着与它相关联的信息,比如运行状态,回调函数等。
由此我们可以知道,同步任务和异步任务会被分发到不同的线程去执行。
现在我们就可以分析一下一下代码的运行结果了。
<span style="font-size: 14px;">setTimeout(()=>{console.log("我才是第一");},0);<br>console.log("我是第一");<br></span>
因为setTimeout是异步的事件,所以主线程把它调入Event Loop线程进行注册。
主线程继续执行<span style="font-size: 14px;">console.log("我是第一");</span>
主线程执行完毕,从Event Loop 线程读取回调函数。再执行<span style="font-size: 14px;">console.log("我才是第一");</span>
;
这里值得一提的是,<span style="font-size: 14px;">setTimeout(callback,0)</span>
指的是主线程中的同步任务运行完了之后立刻由Event Loop 线程调入主线程。
而计时是在调入Event Loop线程注册时开始的,此时<span style="font-size: 14px;">setTimeout的回调函数执行时间</span>
与主线程运行结束的时间相关。
关于setTimeout要补充的是,即便主线程为空,0毫秒实际上也是达不到的。根据HTML的标准,最低是4毫秒。
需要注意的是,此函数是每隔一段时间将回调函数放入Event Loop线程。
一旦setInterval的回调函数fn执行时间超过了延迟时间ms,那么就完全看不出来有时间间隔了
<span style="font-size: 14px;">micro-task(微任务)</span>
与 <span style="font-size: 14px;">macro-task(宏任务)</span>
<span style="font-size: 14px;">Event Loop线程</span>
中包含任务队列(用来对不同优先级的异步事件进行排序),而任务队列又分为<span style="font-size: 14px;">macro-task(宏任务)</span>
与<span style="font-size: 14px;">micro-task(微任务)</span>
,在最新标准中,它们被分别称为<span style="font-size: 14px;">task</span>
与<span style="font-size: 14px;">jobs</span>
。
macro-task大概包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
micro-task大概包括: process.nextTick, Promise, Object.observe(已废弃), MutationObserver(html5新特性)
setTimeout/Promise等我们称之为<span style="font-size: 14px;">任务源</span>
。而进入任务队列的是他们指定的具体执行任务(回调函数)。
来自不同的任务源的任务会进入到不同的任务队列中,而不同的任务队列执行过程如下:
执行过程如下:
JavaScript引擎首先从<span style="font-size: 14px;">macro-task</span>
中取出第一个任务,
执行完毕后,将<span style="font-size: 14px;">micro-task</span>
中的所有任务取出,按顺序全部执行;
然后再从<span style="font-size: 14px;">macro-task</span>
中取下一个,
执行完毕后,再次将<span style="font-size: 14px;">micro-task</span>
中的全部取出;
循环往复,直到两个队列中的任务都取完。
<span style="font-size: 14px;">console.log("start");<br>var promise = new Promise((resolve) => {<br> console.log("promise start..");<br> resolve("promise");<br>}); //3<br>promise.then((val) => console.log(val));<br>setTimeout(()=>{console.log("setTime1")},0);<br>console.log("test end...")<br></span>
这里我们按顺序来分析。
整体script代码作为一个宏任务进入主线程,运行<span style="font-size: 14px;">console.log("start");</span>
。
然后遇到<span style="font-size: 14px;">Promises</span>
直接运行<span style="font-size: 14px;">console.log("promise start..")</span>
。
然后遇到<span style="font-size: 14px;">promise.then</span>
,存入到<span style="font-size: 14px;">micro-task队列</span>
中。
然后遇到<span style="font-size: 14px;">setTimeout</span>
,存入到<span style="font-size: 14px;">macro-task队列</span>
中。
于然后运行<span style="font-size: 14px;">console.log("test end...")</span>
;
在这一轮中,宏任务运行结束,运行micro-task队列中的 <span style="font-size: 14px;">promise.then</span>
,输出<span style="font-size: 14px;">promise</span>
取出<span style="font-size: 14px;">macro-task队列</span>
中的<span style="font-size: 14px;">setTimeout</span>
,运行<span style="font-size: 14px;">console.log("setTime1");</span>
输出的顺序就是
<span style="font-size: 14px;">// start<br>// promise start<br>// test end...<br>// promise<br>//setTime1<br></span>
async function testSometing() { console.log("执行testSometing"); return "testSometing"; } async function testAsync() { console.log("执行testAsync"); return Promise.resolve("hello async"); } async function test() { console.log("test start..."); const v1 = await testSometing(); console.log(v1); const v2 = await testAsync(); console.log(v2); console.log(v1, v2); } test(); var promise = new Promise((resolve) => { console.log("promise start.."); resolve("promise"); }); //3 promise.then((val) => console.log(val)); setTimeout(()=>{console.log("setTime1")},3000); console.log("test end...")
相关推荐:
Detailed explanation of the order of code execution in JavaScript
Detailed introduction to the execution results of the loading order of classes in Java
Detailed explanation of the implementation code of PHP executing external programs
The above is the detailed content of JavaScript execution sequence analysis. For more information, please follow other related articles on the PHP Chinese website!