>웹 프론트엔드 >JS 튜토리얼 >JavaScript 실행 순서 분석

JavaScript 실행 순서 분석

小云云
小云云원래의
2017-12-09 16:30:391758검색

단일 스레드 JavaScript

우선, <code><span style="font-size: 14px;">JavaScript</span>JavaScript단일 스레드 해석 언어라는 것을 알아야 합니다. 이는 동시에 하나의 명령만 실행할 수 있음을 의미합니다. 단일 스레드 언어인 이유는 그 목적과 관련이 있습니다.
JavaScript는 원래 브라우저와 사용자 간의 상호 작용, 특히 양식 상호 작용을 향상시키기 위해 설계되었습니다. 나중에 Ajax 기술도 양식 상호 작용을 보다 인간적으로 만들기 위해 발명되었습니다. JavaScript는 해석된 언어이고 해석기가 브라우저에 내장되어 있으므로 이 해석기는 단일 스레드입니다.
멀티 스레드로 설계되지 않은 이유는 멀티 스레드로 인해 웹 페이지를 렌더링할 때 쉽게 교착 상태나 리소스 충돌이 발생할 수 있기 때문입니다. 그러나 브라우저 자체는 다중 스레드입니다. 예를 들어 네트워크 리소스를 로드하는 동안 JavaScript를 해석하고 실행합니다.

JavaScript는 왜 멀티스레딩을 지원하지 않나요?

dd9bdc1b0d17df9dd579d875a4346d8f{console.log("我才是第一");},0);
console.log("我是第一");

  1. 因为setTimeout是异步的事件,所以主线程把它调入Event Loop线程进行注册。

  2. 主线程继续执行<span style="font-size: 14px;">console.log("我是第一");</span>

  3. 主线程执行完毕,从Event Loop 线程读取回调函数。再执行<span style="font-size: 14px;">console.log("我才是第一");</span>;

setTimeout 和 setInterval

<span style="font-size: 14px;">setTimeout</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毫秒。

setInterval

需要注意的是,此函数是每隔一段时间将回调函数放入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>

这里我们按顺序来分析。

第一轮
  1. 整体script代码作为一个宏任务进入主线程,运行<span style="font-size: 14px;">console.log("start");</span>

  2. 然后遇到<span style="font-size: 14px;">Promises</span>直接运行<span style="font-size: 14px;">console.log("promise start..")</span>

  3. 然后遇到<span style="font-size: 14px;">promise.then</span>,存入到<span style="font-size: 14px;">micro-task队列</span>中。

  4. 然后遇到<span style="font-size: 14px;">setTimeout</span>,存入到<span style="font-size: 14px;">macro-task队列</span>中。

  5. 于然后运行<span style="font-size: 14px;">console.log("test end...")</span>;

  6. 在这一轮中,宏任务运行结束,运行micro-task队列中的 <span style="font-size: 14px;">promise.then</span>,输出<span style="font-size: 14px;">promise</span>

第二轮
  1. 取出<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...")

相关推荐:

자바스크립트 코드 실행 순서 상세 설명

자바 클래스의 로딩 순서 실행 결과 상세 소개

외부 프로그램을 실행하는 PHP 구현 코드 상세 설명

위 내용은 JavaScript 실행 순서 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.