매크로 작업 및 마이크로 작업 및 인터뷰 질문에 대한 자세한 설명

우선 19 년 만에 화제가됐던 인터뷰 질문을 살펴 보겠습니다.

console.log('script start')

async function async1() {
    
    
await async2()
console.log('async1 end')
}
async function async2() {
    
    
console.log('async2 end')
}
async1()

setTimeout(function() {
    
    
console.log('setTimeout')
}, 0)

new Promise(resolve => {
    
    
console.log('Promise')
resolve()
})
.then(function() {
    
    
console.log('promise1')
})
.then(function() {
    
    
console.log('promise2')
})

console.log('script end')

누구나이 면접 질문에 익숙해 져야합니다. 오늘은이 면접 질문을 여유롭게보고 간단한 원리를 살펴 보았습니다. 글이 제자리에 있지 않다면 사장님이 조언을 해주셨 으면합니다.
주요 프로세스
1. 비동기 대기
2. 매크로 작업 및 마이크로 작업
3.이 질문에 대한 간략한 설명

먼저 async await에 대해 이야기하겠습니다.

async await는 Promise 콜백 지옥을 해결하고 코드를 더 명확하고 이해하기 쉽게 만들기위한 ES7의 제품입니다.
async는 Generator 함수의 구문 설탕이며 Generator 함수가 개선되었습니다.

Generator 기능 소개

생성기는 함수와 매우 유사하며 다음과 같이 정의됩니다.

//主要关注点:
//1.*星号
//2.yield
function* foo(x) {
    
    
    yield x + 1;
    yield x + 2;
    return x + 3;
}

위의 기능을 실행하면

hw.next()// { value: 'hello', done: false }
hw.next()// { value: 'world', done: false }
hw.next()// { value: 'ending', done: true }
hw.next()// { value: undefined, done: true }

결과에서 Generator 함수가 호출 될 때 실행되지 않음을 알 수 있으며, 다음 메소드가 호출되고 내부 포인터가 문을 가리킬 때만 실행됩니다. 즉, 함수를 일시 정지 또는 재개 할 수 있습니다. . 반복기 객체의 다음 메서드가 호출 될 때마다 두 개의 속성 값과 done이있는 객체가 반환됩니다. value 속성은 yield 표현식 다음의 표현식 값인 현재 내부 상태의 값을 나타내고 done 속성은 순회가 끝났는지 여부를 나타내는 부울 값입니다.

Generator는 비동기 작업을위한 컨테이너입니다. 자동 실행에는 메커니즘이 필요하며 비동기 작업에 결과가 있으면 실행 권한이 자동으로 반환 될 수 있습니다. 이를 수행하는 두 가지 방법이 있습니다 (다음에 설명 할 매크로 작업 및 마이크로 작업과 관련됨).

1. 콜백 기능. 비동기 작업을 Thunk 함수로 래핑하고 콜백 함수에서 바로 실행을 반환합니다.
2. 약속 개체. 비동기 작업을 Promise 개체로 래핑하고 then 메서드를 사용하여 실행 권한을 반환합니다.

Promise 객체를 기반으로 한 간단한 자동 실행기 :
생성기 함수를 사용하여 위 함수를 구문 분석 할 때 분석은 다음과 같습니다.

function* foo(x) {
    let response1 = yield fetch(x+1) //返回promise对象
    console.log('response1')
    console.log(response1)
    let response2 = yield fetch(x+2) //返回promise对象
    console.log('response2')
    console.log(response2)
}
run(foo);

비동기 / 대기

ES7은 실행자와 생성자에게 작별을 고하고보다 직관적이고 간결한 코드를 얻을 수있는 async / await를 도입했습니다. MDN 정의에 따르면 async는 비동기 적으로 실행되고 결과로 Promise를 암시 적으로 반환하는 함수입니다. async는 Generator 함수의 통 사적 설탕이라고 할 수 있으며 Generator 함수가 개선되었습니다.

이전 기사의 코드는 다음과 같이 비동기로 구현됩니다.

const foo = async () => {
    
    
    let response1 = await fetch(x+1) 
    console.log('response1')
    console.log(response1)
    let response2 = await fetch(x+2) 
    console.log('response2')
    console.log(response2)
}

비교하면 비동기 함수가 Generator 함수의 별표 (*)를 async로 바꾸고 yield를 await로 바꾸는 것임을 알 수 있습니다 (이것이 위에서 언급 한 두 가지 관심사에 대한 이유입니다).

이 시점에서 어떤 사람들은 다음과 같이 말할 수 있습니다.이 실행 방법과 Generator의 차이점은 무엇입니까?

비동기 함수에 의한 Generator 함수의 개선은 다음 네 가지 사항에 반영됩니다.

1. 내장 액추에이터. Generator 함수의 실행은 실행기에 의존해야하며 비동기 함수에는 자체 실행기가 있으므로 next () 메서드를 수동으로 실행할 필요가 없습니다.

2. 더 나은 의미론. Async 및 await는 별표 및 양보보다 명확한 의미를 갖습니다. async는 함수에 비동기 작업이 있음을 나타내고 await는 다음식이 결과를 기다려야 함을 나타냅니다.

3. 더 넓은 적용 가능성. co 모듈은 yield 명령 뒤에 Thunk 함수 또는 Promise 개체 만 올 수 있으며 비동기 함수의 await 명령 뒤에 Promise 개체와 기본 유형 (숫자, 문자열 및 부울)의 값이 올 수 있다는 데 동의합니다. 값이지만 즉시 해결 된 Promise 개체로 자동 변환됩니다.

4. 반환 값은 Promise입니다. 비동기 함수의 반환 값은 Promise 객체로 Generator 함수에서 반환하는 Iterator 객체보다 편리하며 then () 메서드를 사용하여 직접 호출 할 수 있습니다.

매크로 작업 및 마이크로 작업 및 실행 순서

매크로 작업과 마이크로 작업에 관해서는 이벤트 루프를 언급해야합니다 .JS
의 본질 한 줄입니다.

  1. 일반적으로 비 차단 작업은 메인 스레드의 실행 스택에서 직접 동기화되고 완료됩니다.
  2. 일반적으로 블로킹 작업은 비동기 적으로 실행되고 비동기 작업은 일반적으로 완료를 위해 다른 스레드에 전달 된 다음 콜백 함수가 이벤트 큐에 배치됩니다.

메인 스레드의 작업이 실행되면 (실행 스택이 비어 있음) JS는 이벤트 큐를 요청합니다.

매크로 작업 실행 (동기화 코드 먼저 실행)-> 모든 마이크로 작업 실행-> UI 렌더링-> 다음 매크로 작업 실행-> 모든 마이크로 작업 실행-> UI 렌더링-> ...

HTML 표준에 따르면 한 라운드의 이벤트 루프 실행이 종료되면 UI 렌더링이 다음 라운드의 이벤트 루프 실행 전에 시작됩니다. 즉, 매크로 작업이 실행되고 모든 마이크로 작업이 실행 된 후 루프의 현재 라운드가 종료되고 UI 렌더링이 실행됩니다. UI 렌더링이 완료된 후 다음 루프가 이어집니다. 그러나 UI 렌더링에 사용되는 성능은 UI 변경 여부를 고려해야하기 때문에 UI 렌더링이 실행되지 않을 수 있습니다.

매크로 작업

(매크로) 태스크에서 실행 스택이 실행될 때마다 실행되는 코드는 매크로 태스크 (이벤트 큐에서 이벤트 콜백을 가져와 실행을 위해 실행 스택에 배치 할 때마다 포함)임을 알 수 있습니다.

JS 내부 (매크로) 작업과 DOM 작업이 순서대로 실행되도록하기 위해 브라우저는 하나 (매크로) 작업의 실행이 끝난 후 다음 (매크로) 작업이 실행되기 전에 페이지를 다시 렌더링합니다. 작업이 시작됩니다. 프로세스는 다음과 같습니다.

宏任务包含:
script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 环境)

마이크로 태스크

마이크로 태스크는 현재 태스크의 실행이 끝난 직후에 실행되는 태스크로 이해할 수 있습니다. 즉, 현재 작업 후, 다음 작업 전, 렌더링 전입니다.

따라서 렌더링을 기다릴 필요가 없기 때문에 응답 속도가 setTimeout보다 빠릅니다 (setTimeout은 작업 임). 즉, 특정 매크로 작업이 실행 된 후 실행 중에 생성 된 모든 마이크로 작업이 실행됩니다 (렌더링 전).

微任务包含:
Promise.then
Object.observe
MutaionObserver
process.nextTick(Node.js 环境)

이것들을 다 읽고 나면 위의 질문으로 돌아올 것입니다.

console.log('script start')

async function async1() {
    
    
await async2()
console.log('async1 end')
}
async function async2() {
    
    
console.log('async2 end')
}
async1()

setTimeout(function() {
    
    
console.log('setTimeout')
}, 0)

new Promise(resolve => {
    
    
console.log('Promise')
resolve()
})
.then(function() {
    
    
console.log('promise1')
})
.then(function() {
    
    
console.log('promise2')
})

console.log('script end')
// script start => async2 end => Promise => script end => promise1 => promise2 => async1 end => setTimeout

이 코드를 분석하십시오.

1. 코드를 실행하고 스크립트 시작을 출력합니다.

2. async1 ()을 실행하고 async2 ()를 호출하고 async2 end를 출력하면 async1 함수의 컨텍스트는 그대로 유지되고 async1 함수는 점프 아웃됩니다.

3. setTimeout이 발생하면 매크로 작업이 생성됩니다.

4. Promise를 실행하고 Promise를 출력합니다. 그때 만날 때 첫 번째 마이크로 태스크를 생성하십시오.

5. 코드를 계속 실행하고 스크립트를 출력합니다.

6. 코드 로직이 실행 된 후 (현재 매크로 태스크 실행 완료) 현재 매크로 태스크에서 생성 한 마이크로 태스크 큐 실행을 시작하고 promise1을 출력합니다. 마이크로 태스크가 발생하면 새로운 마이크로 태스크가 생성됩니다.

7. 생성 된 마이크로 태스크를 실행하고 promise2를 출력하면 현재 마이크로 태스크 큐가 실행됩니다. async1로 바로 돌아가 실행

8. await를 실행하면 실제로 약속 반환이 생성됩니다.

9.let promise_ = new Promise ((resolve, reject) {resolve (undefined)})
실행 완료, await 후 명령문 실행, async1 end 출력

10. 마지막으로 다음 매크로 작업을 실행합니다. 즉, setTimeout을 실행하고 setTimeout을 출력합니다.

추천

출처blog.csdn.net/lbchenxy/article/details/109382124