VUE3.0을 빠르게 시작하는 방법:
js
인터뷰에서 자주 테스트되는 부분입니다. 어떤 친구들은 물어보면 헷갈릴 수도 있으니, 화면 앞에서 도움이 되셨으면 해서 오늘 요약해보겠습니다.
js
의 실행 컨텍스트와 js
실행 메커니즘에 대해 이야기하기 전에 스레드와 프로세스에 대해 이야기해 보겠습니다.
线程
CPU
스케줄링의 가장 작은 단위입니다.
? 공식적인 용어로进程
CPU
리소스 할당의 가장 작은 단위입니다.
线程
进程
기반으로 하는 프로그램 실행 단위입니다. 일반 용어로 말하면,线程
进程
하나 이상의线程
가질 수 있습니다.
单线程
라는进程
에는 단 하나의 실행 흐름이 있습니다. 즉, 프로그램이 실행될 때 다음 프로그램이 실행되기 전에 이전 프로그램 경로가 연속적으로 정렬됩니다.
进程
의 여러 실행 스트림을多线程
이라고 합니다. 즉, 여러 개의 서로 다른线程
프로그램에서 동시에 실행되어 서로 다른 작업을 수행할 수 있습니다. 즉, 단일 프로그램이 여러 개의 병렬 실행线程
생성하여 해당 작업을 완료할 수 있음을 의미합니다. .
저자는 아래에 간단한 예를 들어 설명하겠습니다. 예를 들어 qq音乐
실행하면 qq音乐
qq音乐
에서 노래를 들으면서 다운로드할 수 있습니다. 노래는 스레드이고 다운로드는 프로세스입니다. 코드를 작성하기 위해 vscode
다시 열면 또 다른 프로세스가 됩니다.
프로세스는 서로 독립적이지만 일부 리소스는 동일한 프로세스의 스레드 간에 공유됩니다.
스레드의 수명주기는 5단계를 거칩니다.
새로운 상태: new
키워드와 Thread
클래스 또는 그 서브클래스를 사용하여 스레드 객체를 생성한 후 스레드 객체는 새로운 상태가 됩니다. 프로그램이 스레드를 start()
때까지 이 상태를 유지합니다.
준비 상태: 스레드 객체가 start()
메서드를 호출하면 스레드는 준비 상태로 들어갑니다. 준비 상태의 스레드는 준비 대기열에 있으며 CPU
사용 권한을 얻는 한 즉시 실행될 수 있습니다.
실행 상태: 준비 상태의 스레드가 CPU
자원을 획득하면 run()
실행할 수 있으며 스레드는 실행 중 상태가 됩니다. 실행 상태의 스레드는 가장 복잡하며 차단되거나 준비되거나 종료될 수 있습니다.
차단 상태: 스레드가 sleep(睡眠)
, suspend(挂起)
, wait(等待)
및 기타 메서드를 실행하면 점유된 리소스를 잃은 후 스레드는 실행 상태에서 차단 상태로 들어갑니다. 대기 시간이 만료되거나 장치 자원을 얻은 후에 다시 준비 상태로 들어갈 수 있습니다. 이는 세 가지 유형으로 나눌 수 있습니다.
대기 차단: 실행 상태의 스레드가 wait()
메소드를 실행하여 스레드가 대기 차단 상태에 들어가게 합니다.
동기 차단: 스레드가 synchronized
동기화 잠금을 획득하는 데 실패합니다(동기화 잠금이 다른 스레드에 의해 점유되어 있기 때문).
기타 차단: 스레드의 sleep()
또는 join()
호출하여 I/O
요청이 발행되면 스레드는 차단 상태로 들어갑니다. sleep()
상태가 시간 초과되면 join()
스레드가 종료되거나 시간 초과될 때까지 기다리거나 I/O
처리가 완료되고 스레드가 준비 상태로 돌아갑니다.
종료 상태: 실행 중인 스레드가 작업을 완료하거나 다른 종료 조건이 발생하면 스레드는 종료된 상태로 전환됩니다.
JS
브라우저 스크립팅 언어로서 JS
주로 사용자와 상호 작용하고 DOM
운영하는 데 사용됩니다. 이는 단일 스레드만 가능하다는 것을 결정합니다. 그렇지 않으면 매우 복잡한 동기화 문제가 발생합니다. 예를 들어 JavaScript
두 개의 스레드가 동시에 있다고 가정해 보겠습니다. 한 스레드는 특정 DOM
노드에 콘텐츠를 추가하고 다른 스레드는 해당 노드를 삭제합니다. 이 경우 브라우저는 어떤 스레드를 사용해야 합니까?
JS
엔진은 실행 가능한 코드 조각(일반적으로 함수 호출 단계)을 구문 분석할 때 먼저 실행 전에 몇 가지 준비 작업을 수행합니다. (실행 컨텍스트( EC
라고도 함)" 또는 실행 환경 이라고도 합니다.
javascript
에는 다음과 같은 세 가지 실행 컨텍스트 유형이 있습니다
. 이는 기본 또는 가장 기본적인 실행 컨텍스트 입니다. 프로그램에는 전역 컨텍스트가 하나만 있으며 수명 주기 내내 존재합니다. javascript
스크립트. 실행 스택의 맨 아래는 스택 팝핑으로 인해 파괴되지 않습니다. 전역 컨텍스트는 전역 개체를 생성하고(브라우저 환경을 예로 들면 이 전역 개체는 window
임) this
값을 이 전역 개체에 바인딩합니다.
함수 실행 컨텍스트 함수가 호출될 때마다 (함수가 반복적으로 호출되는지 여부에 관계없이) 새로운 함수 실행 컨텍스트가 생성됩니다.
Eval 함수 실행 컨텍스트 eval
함수 내에서 실행되는 코드도 자체 실행 컨텍스트를 가지게 되지만, eval
자주 사용되지 않으므로 여기서는 분석하지 않습니다.
앞서 js
실행 중일 때 실행 컨텍스트를 생성한다고 언급했지만 실행 컨텍스트를 저장해야 하는데 이를 저장하는 데 무엇이 사용됩니까? 스택 데이터 구조를 사용해야 합니다.
스택은 선입후출 방식의 데이터 구조입니다.
요약하자면, 코드가 실행될 때 생성된 실행 컨텍스트를 저장하는 데 사용되는 실행 컨텍스트가 실행 스택입니다 .
JS
코드 조각을 실행할 때
그런 다음 JS
엔진은 전역 실행 컨텍스트를 생성하고 push
. 이 프로세스에서 JS
엔진은 이 코드의 모든 변수에 메모리를 할당하고 생성이 완료된 후 초기 값(정의되지 않음)을 할당합니다. JS
엔진은 실행 단계에 들어갑니다. 이 과정에서 JS
엔진은 코드를 한 줄씩 실행합니다. 즉, 메모리가 할당된 변수에 값(실제 값)을 하나씩 할당합니다.
이 코드에 function
호출이 있으면 JS
엔진은 함수 실행 컨텍스트를 생성하고 push
. 생성 및 실행 프로세스는 전역 실행 컨텍스트와 동일합니다.
실행 스택이 완료되면 스택에서 실행 컨텍스트가 팝되고 다음 실행 컨텍스트가 입력됩니다.
아래에 예를 들어 보겠습니다. 프로그램에 다음 코드가 있는 경우:
console.log("Global Execution Context start"); 함수 우선() { console.log("첫번째 함수"); 두번째(); console.log("다시 첫 번째 함수"); } 함수 두 번째() { console.log("두 번째 함수"); } 첫 번째(); console.log("Global Execution Context end");
먼저, 실행 스택이 생성되고
, 그 다음 글로벌 컨텍스트가 생성되고, 실행 컨텍스트가 실행 스택으로 push
실행이 시작됩니다
.
, Global Execution Context start
first
메서드를 만나고, 메서드를 실행하고, 함수 실행 컨텍스트를 생성하고 push
first
실행 컨텍스트를 실행하고, first function
second
메서드를 만나서 메서드를 실행합니다. , 함수 실행 컨텍스트를 생성하고 push
second
실행 컨텍스트를 실행하고 second function
second
실행 컨텍스트가 실행되어 스택에서 팝되고 다음 실행 컨텍스트에 들어갑니다. first
first
실행 컨텍스트가 계속됩니다
실행, 출력 Again first function
실행되고, 스택에서 팝되고, 다음 실행 컨텍스트로 들어갑니다. first
실행 컨텍스트
전역 실행 컨텍스트 실행을 계속하고 출력합니다. Global Execution Context end
그림을 사용하여 요약합니다.
괜찮은. 실행 컨텍스트와 실행 스택에 대해 이야기한 후 js의 실행 메커니즘에 대해 이야기해 보겠습니다. js
의 실행 메커니즘에 대해 이야기하면
js
작업, 매크로 작업 및 마이크로 작업을 js
합니다.
js
에서 작업은 동기 작업과 비동기 작업으로 구분됩니다. 그렇다면 동기 작업은 무엇이고 비동기 작업은 무엇일까요?
동기 작업은 기본 스레드에서 실행 대기 중인 작업을 의미하며, 이전 작업이 실행된 후에만 다음 작업을 실행할 수 있습니다.
비동기 작업은 메인 스레드에 들어가지 않고 "작업 큐"에 들어가는 작업을 의미합니다(작업 큐의 작업은 메인 스레드와 병렬로 실행됩니다). 메인 스레드, 비동기 작업 실행이 가능해지면 작업은 실행을 위해 메인 스레드로 들어갑니다. 대기열 저장소이므로 선입선출 규칙을 충족합니다 . 일반적인 비동기 작업에는 setInterval
, setTimeout
, promise.then
등이 포함됩니다.
이전에 동기 작업과 비동기 작업을 소개했습니다. 이제 이벤트 루프에 대해 이야기하겠습니다.
동기식 및 비동기식 작업은 각각 다른 실행 "위치"에 들어가고 이전 작업이 완료된 경우에만 다음 작업이 실행될 수 있습니다. 비동기 작업은 메인 스레드에 들어가지 않고 Event Table
에 들어가 함수를 등록합니다.
지정된 작업이 완료되면 Event Table
이 기능을 Event Queue
이동합니다. Event Queue
큐 데이터 구조이므로 선입선출 규칙을 충족합니다.
실행 후 메인 스레드의 작업이 비어 있으면 Event Queue
에서 해당 함수를 읽어 메인 스레드에서 실행합니다.
위의 과정이 지속적으로 반복되는데, 이를 흔히 이벤트 루프(Event Loop) 라고 합니다.
사진으로 요약해보자
함수 test1() {를
간략하게 소개하겠습니다
.console.log("log1"); setTimeout(() => { console.log("setTimeout 1000"); }, 1000); setTimeout(() => { console.log("setTimeout 100"); }, 100); console.log("log2"); } test1(); // log1, log2, setTimeout 100, setTimeout 1000
js에서는 동기 작업이 비동기 작업보다 먼저 실행된다는 것을 알고 있으므로 위의 예에서는 log1、log2
먼저 출력한
다음 동기 작업 후에 비동기 작업을 실행합니다. 따라서 100
밀리초 지연된 콜백 함수는 setTimeout 100
출력을 먼저 실행
1000
setTimeout 1000
위의 예는 비교적 간단합니다. 위의 저자가 언급한 동기 및 비동기 작업을 이해하는 한 문제가 없습니다. 그럼 또 다른 예를 들어보겠습니다. 결과가 어떻게 나올지 살펴보겠습니다.
함수 테스트2() { console.log("log1"); setTimeout(() => { console.log("setTimeout 1000"); }, 1000); setTimeout(() => { console.log("setTimeout 100"); }, 100); new Promise((해결, 거부) => { console.log("새 약속"); 해결하다(); }).then(() => { console.log("promise.then"); }); console.log("log2"); } test2();
위의 문제를 해결하려면 동기 및 비동기 작업을 아는 것만으로는 충분하지 않으며 매크로 작업과 마이크로 작업도 알아야 합니다.
js
에서 작업은 두 가지 유형으로 나누어집니다. 하나는 매크로 작업 MacroTask
라고 하고 다른 하나는 마이크로 작업 MicroTask
라고 합니다.
일반적인 매크로 작업 MacroTask
에는
기본 코드 블록인
setTimeout()
setInterval()
setImmediate() - Node
requestAnimationFrame() -
일반적인 마이크로 작업 MicroTask
에는
Promise.then()
process.nextTick() - Node
. 위의 예는 매크로 작업과 마이크로 작업을 포함합니다. 매크로 작업과 마이크로 작업의 실행 순서는 무엇입니까?
우선, 전체 script
(첫 번째 매크로 작업)가 실행되기 시작하면 모든 코드는 동기 작업과 비동기 작업의 두 부분으로 나누어지며, 동기 작업은 순차적으로 실행하기 위해 메인 스레드에 직접 들어갑니다. 비동기 작업은 비동기 대기열에 들어간 다음 매크로 작업과 마이크로 작업으로 나뉩니다.
매크로 작업은 Event Table
들어가고 여기에 콜백 함수를 등록합니다. Event Table
이 Event Queue
이벤트 큐로 이동하고 다른 Event Table
에 등록합니다. . 지정된 이벤트가 완료될 때마다 Event Table
이 기능을 Event Queue
메인 스레드의 작업이 완료되고 메인 스레드가 비어 있으면 마이크로태스크의 Event Queue
확인됩니다. , 모두 실행하고, 그렇지 않은 경우 다음 매크로 작업을 실행합니다.
이를 요약하기 위해 그림을 사용합니다.
위의 비동기 작업과 마이크로 작업의 예를 이해하면 쉽게 답을 얻을 수 있습니다.
우리는 js에서 동기 작업이 비동기 작업보다 먼저 실행된다는 것을 알고 있으므로 위의 예에서는 log1、new promise、log2
먼저 출력합니다. 여기서 주목해야 할 점은 새 Promise의 메인 코드 블록이 동기화된다는 점입니다.
매크로 작업이 실행된 후 이 매크로 작업에 의해 생성된 모든 마이크로 작업이 실행 promise.then
모든 마이크로 작업이 실행된 후
, 다른 매크로 작업이 지연되어 실행됩니다. 100
밀리초의 콜백 함수는 실행 우선 순위를 지정하고 setTimeout 100
출력합니다.
이 매크로 작업은 마이크로 작업을 생성하지 않으므로 다음 매크로 작업을 계속 실행하기 위해 실행해야 하는 마이크로 작업이 없습니다
. 1000
지연된 함수는 실행 우선 순위를 지정하고 setTimeout 1000
출력
하므로 test2 메소드가 실행된 후 log1、new promise、log2、promise.then、setTimeout 100、setTimeout 1000
순서대로 출력합니다
.
js
먼저 매크로 작업으로 실행한 다음 마이크로 작업으로 실행할 것인지 아니면 매크로 작업 전에 마이크로 작업으로 실행할 것인지에 대한 의견이 다릅니다. 저자는js
코드 블록 전체를 매크로 작업으로 간주하면js
실행 순서는 매크로 작업이 먼저이고 그 다음이 마이크로 작업이라고 이해합니다.
속담처럼, 한 번 연습하는 것이 백 번 보는 것보다 낫습니다. 아래에서 두 가지 예를 설명하겠습니다. 올바르게 수행할 수 있다면 js
실행 메커니즘에 대한 지식을 마스터한 것입니다.
예제 1
함수 test3() { console.log(1); setTimeout(함수 () { console.log(2); new Promise(함수 (해결) { console.log(3); 해결하다(); }).then(함수 () { console.log(4); }); console.log(5); }, 1000); new Promise(함수 (해결) { console.log(6); 해결하다(); }).then(함수 () { console.log(7); setTimeout(함수 () { console.log(8); }); }); setTimeout(함수 () { console.log(9); new Promise(함수 (해결) { console.log(10); 해결하다(); }).then(함수 () { console.log(11); }); }, 100); console.log(12); } test3();
먼저, 전체 js
코드 블록이 매크로 태스크로 실행되어 1, 1、6、12
차례로 출력됩니다
.
전체 코드 블록 매크로 태스크가 실행된 후 하나의 마이크로 태스크와 두 개의 매크로 태스크가 생성되므로 매크로 태스크 큐에는 두 개의 매크로 태스크가 있고 마이크로 태스크 큐에는 하나의 마이크로 태스크가 있습니다.
매크로 작업이 실행된 후에는 이 매크로 작업에 의해 생성된 모든 마이크로 작업이 실행됩니다. 마이크로태스크가 하나뿐이므로 7
출력됩니다. 이 마이크로태스크는 또 다른 매크로태스크를 생성했으므로 현재 매크로태스크 대기열에는 3개의 매크로태스크가 있습니다.
3개의 매크로태스크 중 지연이 설정되지 않은 것이 먼저 실행되므로 8
이 출력됩니다. 이 매크로태스크는 마이크로태스크를 생성하지 않으므로 실행할 마이크로태스크가 없으며 다음 매크로태스크가 계속 실행됩니다.
매크로태스크 실행을 100
밀리초 동안 지연하고 9、10
출력하고 마이크로태스크를 생성합니다. 따라서 마이크로태스크 대기열에는 현재 마이크로태스크가 있습니다.
매크로태스크가 실행된 후에는 매크로태스크에 의해 생성된 모든 마이크로태스크가 실행되므로 마이크로태스크가 실행됩니다. 작업 대기열의 모든 마이크로태스크는 11
출력합니다.
매크로태스크 실행은 1000
밀리초의 지연으로 2、3、5
출력하고 마이크로태스크가 생성됩니다. 따라서 마이크로태스크 대기열에는 매크로태스크가
실행된 후 모든 마이크로태스크가 생성되므로 마이크로태스크 대기열의 모든 마이크로태스크가 실행되고 4
출력됩니다
. 따라서 위의 코드 예에서는 1、6、12、7、8、9、10、11、2、3、5、4
, 12, 7, 8, 9, 10, 11이 출력됩니다. , 2, 3, 5, 4 순서대로 잘 하셨나요?
예제 2:
위의 예제 1을 약간 수정하고 async
도입 await
async 함수 test4()를 기다립니다. console.log(1); setTimeout(함수 () { console.log(2); new Promise(함수 (해결) { console.log(3); 해결하다(); }).then(함수 () { console.log(4); }); console.log(5); }, 1000); new Promise(함수 (해결) { console.log(6); 해결하다(); }).then(함수 () { console.log(7); setTimeout(함수 () { console.log(8); }); }); const 결과 = async1()을 기다립니다; console.log(결과); setTimeout(함수 () { console.log(9); new Promise(함수 (해결) { console.log(10); 해결하다(); }).then(함수 () { console.log(11); }); }, 100); console.log(12); } 비동기 함수 async1() { 콘솔.로그(13) return Promise.resolve("Promise.resolve"); } test4();
위의 예는 무엇을 출력합니까? 여기서 우리는 async
및 await
문제를 쉽게 해결할 수 있습니다.
우리는 async
와 await
실제로 Promise
의 구문 설탕이라는 것을 알고 있습니다. 여기서는 await
Promise.then
과 동일하다는 점만 알면 됩니다. 따라서 위의 예를 다음 코드로 이해할 수 있습니다.
function test4() { console.log(1); setTimeout(함수 () { console.log(2); new Promise(함수 (해결) { console.log(3); 해결하다(); }).then(함수 () { console.log(4); }); console.log(5); }, 1000); new Promise(함수 (해결) { console.log(6); 해결하다(); }).then(함수 () { console.log(7); setTimeout(함수 () { console.log(8); }); }); new Promise(함수 (해결) { console.log(13); return resolve("Promise.resolve"); }).then((결과) => { console.log(결과); setTimeout(함수 () { console.log(9); new Promise(함수 (해결) { console.log(10); 해결하다(); }).then(함수 () { console.log(11); }); }, 100); console.log(12); }); } test4();
위 코드를 보면 쉽게 결과를 알 수 있나요?
먼저 전체 js
코드 블록은 초기에 매크로 태스크로 실행되어 1、6、13
차례로 출력합니다.
전체 코드 블록 매크로 태스크가 실행된 후 두 개의 마이크로 태스크와 하나의 매크로 태스크가 생성되므로 매크로 태스크 큐에는 하나의 매크로 태스크가 있고 마이크로 태스크 큐에는 두 개의 마이크로 태스크가 있습니다.
매크로 작업이 실행된 후에는 이 매크로 작업에 의해 생성된 모든 마이크로 작업이 실행됩니다. 따라서 7、Promise.resolve、12
출력됩니다. 이 마이크로태스크는 두 개의 매크로태스크를 더 생성했으므로 현재 매크로태스크 대기열에는 세 개의 매크로태스크가 있습니다.
3개의 매크로태스크 중 지연이 설정되지 않은 것이 먼저 실행되므로 8
이 출력됩니다. 이 매크로태스크는 마이크로태스크를 생성하지 않으므로 실행할 마이크로태스크가 없으며 다음 매크로태스크가 계속 실행됩니다.
매크로태스크 실행을 100
밀리초 동안 지연하고 9、10
출력하고 마이크로태스크를 생성합니다. 따라서 마이크로태스크 대기열에는 현재 마이크로태스크가 있습니다.
매크로태스크가 실행된 후에는 매크로태스크에 의해 생성된 모든 마이크로태스크가 실행되므로 마이크로태스크가 실행됩니다. 작업 대기열의 모든 마이크로태스크는 11
출력합니다.
매크로태스크 실행은 1000
밀리초의 지연으로 2、3、5
출력하고 마이크로태스크가 생성됩니다. 따라서 마이크로태스크 대기열에는 매크로태스크가
실행된 후 생성된 모든 마이크로태스크는 마이크로태스크 대기열의 모든 마이크로태스크를 실행하고 4
출력합니다.
따라서 위의 코드 예제는 1, 6, 13, 7 1、6、13、7、Promise.resolve、12、8、9、10、11、2、3、5、4
출력합니다. 1、6、13、7、Promise.resolve、12、8、9、10、11、2、3、5、4
4, 다들 잘 하셨나요?
많은 친구들은 아직 setTimeout(fn)
이해하지 못할 수도 있습니다. 지연 시간이 설정되지 않은 것이 당연하지 않습니까?
setTimeout(fn)
setTimeout(fn,0)
으로 이해할 수 있는데 이는 실제로 같은 의미입니다.
js는 동기 작업과 비동기 작업으로 구분되는 것으로 알고 있습니다. setTimeout(fn)
은 비동기 작업이므로 여기서 지연 시간을 설정하지 않더라도 비동기 대기열에 들어가고 메인 스레드가 실행될 때까지 실행되지 않습니다. 게으른.
저자가 다시 언급하겠지만, setTimeout
, js
이후에 설정한 지연 시간이 우리의 지연 시간에 따라 반드시 실행될 것이라고 생각하시나요? 우리가 설정한 시간은 콜백 함수가 실행될 수 있을 뿐이지만, 메인 스레드가 사용 가능한지 여부는 또 다른 문제입니다.
함수 테스트5() { setTimeout(함수 () { console.log("setTimeout"); }, 100); 내가 = 0이라고 하자; 동안 (참) { 나++; } } test5();
위의 예에서는 100
밀리초 후에 setTimeout
출력됩니까? 아니오, 주 스레드가 무한 루프에 진입하여 비동기 대기열 작업을 실행할 시간이 없기 때문입니다.
GUI渲染
에 대해 언급했는데, 일부 친구들은 이해하지 못할 수도 있습니다. 나중에 브라우저에 관한 기사에서 자세히 소개하겠습니다.
JS引擎线程
와 GUI渲染线程
상호 배타적이므로宏任务
과 DOM任务
순서대로 진행될 수 있도록 브라우저는 하나의宏任务
실행 결과가 나온 후와 다음 작업이 완료되기 전에 GUI渲染线程
시작합니다. 다음宏任务
실행, 페이지 렌더링.
따라서 매크로 작업, 마이크로 작업, GUI 렌더링의 관계는 다음과 같습니다.
매크로 작업 -> 마이크로 작업 -> GUI 렌더링 -> 매크로 작업 ->...
[관련 영상 튜토리얼 추천 : 웹 프론트엔드]
위 내용은 JavaScript 심층 분석 실행 컨텍스트 및 실행 메커니즘에 대한 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참고하세요!