Heim >Web-Frontend >js-Tutorial >Analyse der JavaScript-Ausführungssequenz
Zuerst müssen wir wissen, dass <code><span style="font-size: 14px;">JavaScript</span>
JavaScript ist eine GateSingle-Threaded-interpretierte
Sprache. Das bedeutet, dass wir jeweils nur einen Befehl ausführen können. Der Grund, warum es sich um eine Single-Threaded-Sprache handelt, hängt mit ihrem Zweck zusammen.
JavaScript wurde ursprünglich entwickelt, um die Interaktion zwischen dem Browser und dem Benutzer zu verbessern, insbesondere die Interaktion mit dem Formular. Später wurde auch die Ajax-Technologie erfunden, um die Interaktion mit dem Formular menschlicher zu gestalten. Da JavaScript eine interpretierte Sprache ist und der Interpreter in den Browser eingebettet ist, ist dieser Interpreter Single-Threaded. Der Grund, warum es nicht für Multithreading konzipiert ist, liegt darin, dass Multithreading beim Rendern von Webseiten leicht zu Deadlocks oder Ressourcenkonflikten führen kann. Der Browser selbst ist jedoch multithreaded. Er interpretiert und führt beispielsweise JavaScript aus, während er Netzwerkressourcen lädt.
Warum unterstützt JavaScript kein Multithreading?
3680651bc111395ee83abe0dbe878b10
Einzelner Thread bedeutet, dass, wenn Sie viele Befehle ausführen möchten, diese Befehle im Allgemeinen in der Reihenfolge von oben sortiert werden müssen nach unten (Da der Interpreter am Anfang der Datei beginnt). Beispielsweise wird der folgende Code der Reihe nach ausgeführt.
<span style="font-size: 14px;">console.log("1");<br>console.log("2");<br>console.log("3");<br>//1<br>//2<br>//3<br></span>
Aber wir wissen auch, dass es in JavaScript asynchrone Programmierung gibt, wie Ajax, setTimeout, setInterval oder Promise, async, waiting in ES6.
Die Ausführung eines Befehls im Computer bedeutet, dass er zu diesem Zeitpunkt Ressourcen wie die CPU verwendet. Daher gibt es viele Befehle, die CPU-Ressourcen erhalten möchten Die CPU führt Befehle aus. Es dauert auch Zeit, das Ergebnis zu berechnen und zu erhalten, daher gibt es das Konzept von synchron und asynchron.
Synchronisierung bedeutet, dass bei Ausgabe einer CPU-Anfrage die CPU-Anfrage erst zurückgegeben wird, wenn das Ergebnis vorliegt. Sobald der Anruf jedoch zurückkehrt, erhalten Sie den Rückgabewert.
Asynchron bedeutet, dass der Aufruf nach Ausgabe der CPU-Anfrage direkt zurückkehrt, sodass kein Ergebnis zurückgegeben wird. Nachdem der Vorgang abgeschlossen ist, sind eine Reihe von Mitteln erforderlich, um den Rückgabewert zu erhalten
Zu diesem Zeitpunkt müssen die Konzepte Prozess und Thread eingeführt werden.
Konzept: Ein Prozess ist ein Prozess mit bestimmten Der dynamische Ausführungsprozess eines Programms mit unabhängigen Funktionen in einem Datensatz ist eine unabhängige Einheit für die Ressourcenzuweisung und -planung durch das Betriebssystem und der Träger für die Anwendungsausführung.
Da der Prozess die CPU abwechselnd nutzt, gibt es einen Prozesswechsel, aber aufgrund des aktuellen Programms Alle sind relativ groß und der Switching-Overhead ist sehr hoch, wodurch CPU-Ressourcen verschwendet werden. Daher wurden Threads erfunden, um einen großen Prozess zur gemeinsamen Ausführung in mehrere Threads zu zerlegen.
Ein Prozess ist die kleinste Einheit für das Betriebssystem, um Ressourcen zuzuweisen, und ein Thread ist die kleinste Einheit zur Programmausführung.
Ein Prozess besteht aus einem oder mehreren Threads, die unterschiedliche Ausführungsrouten von Code in einem Prozess darstellen;
Und der Multiprozess bedeutet, dass, während die Berühmtheit Ramen in Ichiraku Ramen isst, der lüsterne Unsterbliche das Mädchen beim Baden beobachtet~~. Der lustvolle Unsterbliche ist ein einziger Prozess und ein einziger Thread, um einen Blick darauf zu werfen!
Threads des Browsers
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...")
相关推荐:
Detaillierte Erläuterung der Reihenfolge der Codeausführung in JavaScript
Detaillierte Erläuterung der Ausführungsergebnisse der Ladereihenfolge von Klassen in Java
Detaillierte Erläuterung des Implementierungscodes von PHP, der externe Programme ausführt
Das obige ist der detaillierte Inhalt vonAnalyse der JavaScript-Ausführungssequenz. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!