[Promise] Promise use/callback hell problem async-await/macro queue and micro queue

Table of contents

1. Review and review knowledge 

1. Function objects and instance objects

2. Callback function (key understanding)

2.1 What is a callback function?

2.2 Classification of callback functions

3. Error

3.1 Types of errors

3.2 Error Handling

3.3 Error objects

2. The understanding and use of Promise

1, promise understanding

1.1 What are promises?

1.2 Promise state changes

1.3 The basic process of promise

2. The use of Promise

2.1. Important grammar

2.2. Basic coding process

2.3 Use 1: promise basic coding process

2.4 Use 2: Use promise to encapsulate timer-based asynchrony

2.5 Use 3: Use promise to encapsulate ajax asynchronous request

3. Promise API

3.1 Promise constructor: new Promise (executor) { }

3.2 Promise.prototype.then method: Promise instance. then(onFulfilled, onRejected)

3.3 Promise.prototype.catch method: Promise instance. catch (onRejected)

3.4 Promise.resolve(value) / Promise.reject( reason )

3.5 Promise.all(promiseArr)

3.6 Promise.race(promiseArr)

3.7 Several key issues of Promise

4. Promise solves the callback hell problem

4.1 Callback hell

4.2 chain call of then

4.3 The chain call of then solves the callback hell (not the best method)

4.4 Breaking Promise Chains

4.5 False Penetration

4.6 async - await solves callback hell (ultimate solution

5. Promise advantages

3. Macro queue and micro queue

1 Overview

2. Related interview questions

2.1 Question Type 1

2.2 Question Type 2

2.3 Question type three


1. Review and review knowledge 

1. Function objects and instance objects

Function object : When a function is used as an object, it is simply called a function object.

    <script>
        function Person(name, age) {
            this.name = name;
            this.age = age;
        }
        Person.sex = 'boy';
        console.log(Person.sex);
        console.log(Person.name); // Person.name 默认是构造函数名,无法自己定义
    </script>

Instance object : the object generated by new constructor or class, we call it instance object.

 const p = new Person('zs', 20);
 console.log(p); // Person {name: "zs", age: 20}

2. Callback function (key understanding)

2.1 What is a callback function?

What we defined, we did not call , and finally executed.

2.2 Classification of callback functions

(1) Synchronous callback function:

Understanding: Execute immediately on the main thread and will not be placed in the callback queue .

Example: array traversal related callback function / executor function of Promise.

(2) Asynchronous callback function:

Understanding: It will not be executed immediately, but will be put into the callback queue and executed later.

For example: timer callback/ajax callback/ promise success and failure callback.

JS execution order:

Event loop:

3. Error

Official documentation: Error - JavaScript | MDN

3.1 Types of errors

Error all false parent types
ReferenceError The referenced variable does not exist
TypeError Incorrect data type
SyntaxError Grammatical errors

3.2 Error Handling

Catch errors: try{ } catch(){ }

MDN docs: try...catch - JavaScript | MDN

try {
  nonExistentFunction();
} catch (error) {
  console.error(error);
  // expected output: ReferenceError: nonExistentFunction is not defined
  // Note - error messages will vary depending on browser
}

Throw an error: throw error

3.3 Error objects

message attribute: error related information.

stack attribute: record information.

2. The understanding and use of Promise

1, promise understanding

1.1 What are promises?

Abstract expression :

(1) Promise is a new technology (ES6 specification).

(2) Promise is a new solution for asynchronous programming in JS (the old solution is: simply use callback functions ).

Concrete expression:

(1) Syntactically: Promise is a constructor.

(2) From a functional point of view: the promise object is used to encapsulate an asynchronous operation and can obtain its success/failure result value.

understand:

(1) Promise is not a callback, but a built-in constructor, which is called by the programmer's own new.

(2) When creating a new Promise, a callback function ( executor function ) must be passed in, which is a synchronous callback and will be executed immediately on the main thread.

(3) The executor function will receive two parameters , both of which are functions, which are received with formal parameters: resolve and reject respectively.

① Calling resolve will change the state of the Promise instance to: fulfilled , and you can specify the successful value.

② Calling reject will change the state of the Promise instance to: failed (rejected) , and you can specify the reason for the failure.

Note: The callback function executor itself is synchronous, and the functions in the executor are asynchronous.

1.2 Promise state changes

Each Promise instance has 3 states, namely: initialization (pending), success (fulfilled), failure (rejected).

The moment each Promise instance is new out, the state is initialization (pending) .

The state of a Promise can only change once , and there are only two kinds of changes: pending => fulfilled ; pending => rejected .

1.3 The basic process of promise

2. The use of Promise

2.1. Important grammar

new Promise(executor) constructor
Promise.prototype.then() method

2.2. Basic coding process

1. Create a Promise instance object (pending state) and pass it to the executor function 2. Start an asynchronous task (timer, ajax request)
in the executor 3. Do different processing according to the result of the asynchronous task:         3.1 If the asynchronous task succeeds:             We call resolve(value) to make the state of the Promise instance object become fulfilled (fulfilled), and at the same time specify the successful value         3.2. If the asynchronous task fails:             we call reject(reason) to make the state of the Promise instance object become rejected (rejected) , while specifying the reason for the failure





 

4. Use the then method to specify success and failure callback functions for the Promise instance to obtain the success value and failure reason
        Note: The success callback and failure callback specified by the then method are all asynchronous callbacks.

5. Points to note about status:
    1. Three statuses:
        pending: undetermined ----- initial status
        fulfilled: successful ------ status after calling resolve()
        rejected: failed --- --- State after calling reject( )
    2. The two states change
        pending => fulfilled
        pending => rejected
    3. The state can only be changed once!!
    4. If a promise specifies multiple success/failure callback functions, will they all be called? meeting!


2.3 Use 1: promise basic coding process

<script>
// 1) 创建 promise 对象(pending 状态), 指定执行器函数
const p = new Promise((resolve, reject) => {
// 2) 在执行器函数中启动异步任务
setTimeout(() => {
    const time = Date.now()
    // 3) 根据结果做不同处理
    if (time % 2 === 1) {
        // 3.1) 如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状态
        resolve('成功的值 '+ time) } else { 
        // 3.2) 如果失败了, 调用 reject(), 指定失败的 reason, 变为rejected 状态
        reject('失败的值' + time) }
    }, 2000)
})
// 4) 能 promise 指定成功或失败的回调函数来获取成功的 vlaue 或失败的 reason
p.then(
    value => { // 成功的回调函数 onResolved, 得到成功的 vlaue
        console.log('成功的 value: ', value)
    },
    reason => { // 失败的回调函数 onRejected, 得到失败的 reason
        console.log('失败的 reason: ', reason) 
    } 
)
</script>

2.4 Use 2: Use promise to encapsulate timer-based asynchrony

<script>
        function doDelay(time) {
            // 1. 创建 promise 对象
            return new Promise((resolve, reject) => {
                // 2. 启动异步任务
                console.log('启动异步任务')
                setTimeout(() => {
                    console.log('延迟任务开始执行...')
                    const time = Date.now() // 假设: 时间为奇数代表成功, 为偶数代表失败
                    if (time % 2 === 1) { // 成功了
                        // 3. 1. 如果成功了, 调用 resolve()并传入成功的 value
                        resolve('成功的数据 ' + time)
                    } else { // 失败了
                        // 3.2. 如果失败了, 调用 reject()并传入失败的 reason
                        reject('失败的数据 ' + time)
                    }
                }, time)
            })
        }
        const promise = doDelay(2000)
        promise.then(
            value => {
                console.log('成功的 value: ', value)
            },
            reason => {
                console.log('失败的 reason: ', reason)
            },
        )
    </script>

2.5 Use 3: Use promise to encapsulate ajax asynchronous request

 <script>
        /*
        可复用的发 ajax 请求的函数: xhr + promise
        */
        function promiseAjax(url) {
            return new Promise((resolve, reject) => {
                const xhr = new XMLHttpRequest()
                xhr.onreadystatechange = () => {
                    if (xhr.readyState !== 4) return
                    const { status, response } = xhr
                    // 请求成功, 调用 resolve(value)
                    if (status >= 200 && status < 300) {
                        resolve(JSON.parse(response))
                    } else { // 请求失败, 调用 reject(reason)
                        reject(new Error('请求失败: status: ' + status))
                    }
                }
                xhr.open("GET", url)
                xhr.send()
            })
        }
        promiseAjax('https://api.apiopen.top2/getJoke?page=1&count=2&type=video').then(
            data => {
                console.log('显示成功数据', data)
            },
            error => {
                alert(error.message)
            })
    </script>

3. Promise API

3.1 Promise constructor: new Promise (executor) { }

Executor function : is executed synchronously, (resolve, reject) => { }

resolve function : call resolve to change the internal state of the Promise instance to successful (fulfiled).

reject function : call reject to change the internal state of the Promise instance to failed (rejected).

Description : The executor function will be called synchronously inside the Promise immediately, and the asynchronous code is placed in the executor function .

3.2 Promise.prototype.then method: Promise instance. then(onFulfilled, onRejected)

onFulfilled : Successful callback function - (value) => { }

onRejected : callback function for failure - (reason) => { }

Note : the then method will return a new Promise instance object.

3.3 Promise.prototype.catch method: Promise instance. catch (onRejected)

onRejected : callback function for failure - (reason) => { }

Explanation : The catch method is the grammatical sugar of the then method, which is equivalent to: then(undefined, onRejected) .

The reject function is executed in the executor:

The callback function in the first p.then method only specifies a successful callback, but does not specify a failed callback, which will generate an error and an uncaught exception ( Uncaught ... )

The second p.catch method is actually a grammatical sugar of p.then. It does not specify a successful callback by default, but only specifies a failed callback , and then outputs the information of the reject function.

In addition: if the resolve function is executed in the executor, and no successful callback is specified below, no error will be reported.

3.4 Promise.resolve(value) / Promise.reject( reason )

Promise.resolve(value):

Description: It is used to quickly return a Promise instance object whose status is fulfilled or rejected .

Note: The value of value may be: (1) Non-Promise values, such as arrays, strings and so on . (2) Promise value.

① If reject is called first, the failed Promise value is returned, and then resolve is called, and finally the failed Promise value is still returned.

②If resolve is called first, the successful Promise value is returned, then reject is called, and the failed Promise callback function is finally executed, but reason is the previous successful Promise value

 Promise.reject(reason): It is used to quickly return a Promise instance object whose status must be rejected.

 ​         

    

// 测试:如果方法给的是 p0 参数,打印出各种可能的结果
    // 为了方便看,不进行代码的注释。
    <script>
        // resolve - resolve
        const p0 = Promise.resolve('ok');
        const p = Promise.resolve(p0); // succ:  ok
 
        // reject - reject
        const p0 = Promise.reject('no!');
        const p = Promise.reject(p0); //fail:  Promise {<rejected>: "no!"} + 报错:Uncaught (in promise) no!
 
        // resolve - reject
        const p0 = Promise.resolve('ok');
        const p = Promise.reject(p0); // fail:  Promise {<fulfilled>: "ok"}
 
        // reject - resolve
        const p0 = Promise.reject('no!');
        const p = Promise.resolve(p0); // fail:  no!
 
        p.then(
            (value) => { console.log('succ: ', value); },
            (reason) => { console.log('fail: ', reason); }
        )
    </script>

3.5 Promise.all(promiseArr)

promiseArr: An array containing n Promise instances.

Description : Return a new Promise instance, only if all the promises succeed , the successful value is the set of all the successful promise values; as long as one fails, it will fail directly , and once it encounters a failed Promise, it will directly return the failed Promise Value, don't care about the promise value behind.

    <script>
        const p1 = Promise.resolve('0');
        const p2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                // resolve('500');
                reject('500');
            }, 500)
        });
        const p3 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('2000');
            }, 2000)
        })
        const x = Promise.all([p1, p2, p3]);
        const then = x.then(
            (value) => { console.log('success', value); },
            (reason) => { console.log('fail', reason); }   // 'fail', '2000'
        )
    </script>

3.6 Promise.race(promiseArr)

promiseArr: An array containing n Promise instances.

Description : Returns a new Promise instance and returns the value of the first promise instance.

3.7 Several key issues of Promise

1. How to change the state of a Promise instance?

  • Execute resolve (value): If it is currently pending, it will become fulfilled
  • Execute reject (reason): If it is currently pending, it will become rejected
  • The executor function (executor) throws an exception: if it is currently pending, it will become rejected

The Promise state can only be changed once, and the above will return success, and subsequent undefined exceptions will not cause the Promise state to change.

2. Which one should change the state of the Promise instance and specify the callback function first?
        ① It is possible. Under normal circumstances, the callback is specified first and then the state is changed , but it is also possible to change the state first and then specify the callback


       ②How to change the state first and then specify the callback?
                Delay for a while and then call then( )


        ③When can the Promise instance get the data?
                If the callback is specified first, then when the state changes, the callback function will be called to get the data.
                If the state is changed first, then when the callback is specified, the callback function will be called to get the data.

3. Promise instance.then() returns a [new Promise instance], what determines its value and state? 1. 
                Simple expression: the execution result of the callback function specified by then() is determined.
                2. Detailed expression:
                        (1) If the callback specified by then returns a non- Promise value a:                                     then [new Promise instance] status is: successful (fulfilled) , and the successful value is a.                         (2) If the callback specified by then returns a Promise instance p:                                     then the state and value of [new Promise instance] are consistent with p .                         (3) If the callback specified by then throws an exception:                                      then the state of [new Promise instance] is rejected, and reason is the exception thrown.




      

 p.then output successfully 1, a, the return value is 900, which is a non-Promise value,

Then call x.then and return 2,900 successfully.

     

 p.then output failed 1, a, the return value is undefined, which is a non-Promise value,

Then call x.then, return 2 successfully, undefined.

   

    

4. Promise solves the callback hell problem

4.1 Callback hell

What is callback hell?

The callback function is called nestedly , and the result of the asynchronous execution of the external callback function is the condition for the execution of the nested callback.

For example: It is required to start the second request after the first request is successful, and then start the third request after the second request, resulting in layer-by-layer nesting.

Disadvantages of callback hell: it is not easy for programmers to read, it is not convenient for exception handling, and it is not convenient for later maintenance.

4.2 chain call of then

Promise instance. then( ) returns a new Promise instance whose value and state are determined by the execution result of the callback function specified by then().

(1) If the callback specified by then returns a non- Promise value a: the state of the new Promise instance is fulfilled, and the successful value is a.

    <script>
        const p = new Promise((resolve, reject) => {
            resolve('a');
        })
 
        const x = p.then(
            (value) => { console.log('succ_then1:', value); }, // succ_then1: a
            (reason) => { console.log('fail_then1:', reason); }
        )
 
        x.then(
            (value) => { console.log('succ_then2:', value); }, // succ_then2: undefined
            (reason) => { console.log('fail_then2:', reason); }
        )
    </script>
    <script>
        const p = new Promise((resolve, reject) => {
            resolve('a');
        })
 
        const x = p.then(
            (value) => { console.log('succ_then1:', value); return false }, // succ_then1: a
            (reason) => { console.log('fail_then1:', reason); }
        )
 
        x.then(
            (value) => { console.log('succ_then2:', value); }, // succ_then2: false
            (reason) => { console.log('fail_then2:', reason); }
        )
    </script>

(2) If the callback specified by then returns a Promise instance p: the state and value of the new Promise instance are consistent with p.

    <script>
        const p = new Promise((resolve, reject) => {
            resolve('a');
        })
 
        const x = p.then(
            (value) => { console.log('succ_then1:', value); return Promise.resolve('a') }, // succ_then1: a
            (reason) => { console.log('fail_then1:', reason); }
        )
 
        x.then(
            (value) => { console.log('succ_then2:', value); }, // succ_then2: a
            (reason) => { console.log('fail_then2:', reason); }
        )
    </script>
    <script>
        const p = new Promise((resolve, reject) => {
            resolve('a');
        })
 
        const x = p.then(
            (value) => { console.log('succ_then1:', value); return Promise.reject('a') }, // succ_then1: a
            (reason) => { console.log('fail_then1:', reason); }
        )
 
        x.then(
            (value) => { console.log('succ_then2:', value); },
            (reason) => { console.log('fail_then2:', reason); } // fail_then2: a
        )
    </script>

(3) If the callback specified by then throws an exception: the state of the new Promise instance is rejected, and reason is the thrown exception.

    <script>
        const p = new Promise((resolve, reject) => {
            resolve('a');
        })
 
        const x = p.then(
            (value) => { console.log('succ_then1:', value); throw 404 }, // succ_then1: a
            (reason) => { console.log('fail_then1:', reason); }
        )
 
        x.then(
            (value) => { console.log('succ_then2:', value); }, 
            (reason) => { console.log('fail_then2:', reason); } // fail_then2: 404
        )
    </script>

Comprehensive case:

    <script>
        const p = new Promise((resolve, reject) => {
            resolve('a');
        })
 
        p.then(
            (value) => { console.log('succ_then1:', value); throw 404 }, // succ_then1: a
            (reason) => { console.log('fail_then1:', reason); return 10 }
        ).then(
            (value) => { console.log('succ_then2:', value); return 100 },
            (reason) => { console.log('fail_then2:', reason); return Promise.reject('20') } // fail_then2: 404
        ).then(
            (value) => { console.log('succ_then3:', value); return true },
            (reason) => { console.log('fail_then3:', reason); return false } // fail_then3: 20
        ).then(
            (value) => { console.log('succ_then4:', value); },
            (reason) => { console.log('fail_then4:', reason); } // succ_then4: false
        )
    </script>

4.3 The chain call of then solves the callback hell (not the best method)

Explanation: When the first request is successful, call the successful callback of value => { } and return a Promise instance (the instance of the second request). According to the description of then() method in the previous point, if the callback specified by then returns the Promise instance p, the state and value of the new Promise instance are consistent with p. So in fact we are passing the Promise instance of the second request as the return value of the first then.

        promiseAjax(url)
            .then(
                value => {
                    console.log('显示第1次成功的数据', value);
                    // 返回第二次请求的实例
                    return promiseAjax(url)
                },
                reason => { alert(reason.message); }
            )

Complete code:

    <script>
        // 定义一个发送请求的函数,返回一个新的 Promise 实例(封装了 ajsx 异步任务)
        function promiseAjax(url) {
            return new Promise((resolve, reject) => {
                const xhr = new XMLHttpRequest();
                xhr.onreadystatechange = () => {
                    if (xhr.readyState !== 4) return;
                    const { status, response } = xhr;
                    if (status >= 200 && status < 300) {
                        // 请求成功, 调用 resolve(value)
                        resolve(JSON.parse(response));
                    } else {
                        // 请求失败, 调用 reject(reason)
                        reject(new Error('请求失败: status: ' + status));
                    }
                }
                xhr.open("GET", url);
                xhr.send();
            })
        }
        
        // 定义正确和错误的 url 地址便于之后的测试
        const url = 'https://api.apiopen.top/api/getHaoKanVideo?page=0&size=2';
        const url_error = 'https://api.apiopen.top/api22/getHaoKanVideo?page=0&size=2';
 
        // then 的链式调用解决回调地狱问题
        promiseAjax(url)
            .then(
                value => {
                    console.log('显示第1次成功的数据', value);
                    return promiseAjax(url)
                },
                reason => { alert(reason.message); }
            )
            .then(
                value => {
                    console.log('显示第2次成功的数据', value);
                    return promiseAjax(url)
                },
                reason => { alert(reason.message); }
            )
            .then(
                value => {
                    console.log('显示第3次成功的数据', value);
                    return promiseAjax(url)
                },
                reason => { alert(reason.message); }
            )
            .then(
                value => {
                    console.log('显示第4次成功的数据', value);
                    return promiseAjax(url)
                },
                reason => { alert(reason.message); }
            )
 
    </script>

4.4 Breaking Promise Chains

The problem arises: If we run the code in 4.3, assuming that the second request fails, an ERROR error will be thrown, and the reason => {} failed callback will be called, but unfortunately we did not return a value to the failed callback , so return undefined. And undefined happens to be a non-Promise value, which leads to success in subsequent requests! This is obviously wrong.

Problem solved: After the request fails, the request will not continue.

Solution: Return a pending Promise instance for each failed callback.

        promiseAjax(url)
            .then(
                value => {
                    console.log('显示第1次成功的数据', value);
                    return promiseAjax(url_error)
                },
                reason => { alert(reason.message); return new Promise(() => { }) }
            )
            .then(
                value => {
                    console.log('显示第2次成功的数据', value);
                    return promiseAjax(url)
                },
                reason => { alert(reason.message); return new Promise(() => { }) }
            )

4.5 False Penetration

Problem: We have to specify a failure callback in each then() method, and need to return a value to break the Promise chain. These failure callback codes are very similar, which is cumbersome.

Solution: Use the .catch() method to catch the bottom line.

Basic idea: We use the .catch() method to specify a failure callback for all errors . The actual idea is that although we do not specify a failure callback in the then() method, the bottom layer makes up for us reason => {throw reason }, if the callback specified by then throws an exception, the state of the new Promise instance is rejected, and reason is the thrown exception. So in fact the reason keeps passing the failure callback to the .catch() method, eventually throwing an exception.

        promiseAjax(url)
            .then(
                value => {
                    console.log('显示第1次成功的数据', value);
                    return promiseAjax(url_error)
                },
                // 我们虽然没有写失败的回调,但实际上底层为我们补了以下代码:
                // reason => {throw reason}
            )
            .then(
                value => {
                    console.log('显示第2次成功的数据', value);
                    return promiseAjax(url)
                },
                // 我们虽然没有写失败的回调,但实际上底层为我们补了以下代码:
                reason => {throw reason}
            )
            .catch(
                reason => { alert(reason.message); }
            )

4.6 async - await solves callback hell (ultimate solution)

Grammar description:

(1) async modified function:

① The return value of the function is a promise object.

② The result of the promise instance is determined by the return value of the async function execution.

(2) await expression:

① If the expression is a promise instance object, the return value after await is the promise success value.

② If the expression is another value, directly use this value as the return value of await (equivalent to an assignment operation, it seems useless...)

(3) Note:

await must be written in the async function, but there can be no await in the async function (it seems useless to write async in front of the simple function...).

②If the promise instance object of await fails, an exception will be thrown , which needs to be captured and processed by try...catch.

async-await syntax:

// 函数形式写法
async function demo() {
    try {
        const result = await promiseAjax(url);
        console.log(result);
        console.log(100);
    } catch (error) {
        console.log(error);
    }
}
demo();
 
// 箭头函数形式写法
// 注意:如果前面没分号,需要在函数前面加分号或者感叹号,否则会报错。
(async () => {
    try {
        const result = await promiseAjax(url);
        console.log(result);
        console.log(100);
    } catch (error) {
        console.log(error);
    }
})()

The principle of await:

If we use async with await:
1. There is no callback function on the surface.
2. But in fact, the bottom layer processed the code we wrote, and "restored" the callback function back.
3. The final running code still has a callback, but the programmer does not see it.

        (async () => {
            try {
                // 程序员“实际上”的写法
                const result = await promiseAjax(url);
                console.log(result);
                console.log(100);
 
                // 浏览器翻译后的代码(表面上没有调then,实际上调了then)
                promiseAjax(url).then(
                     (value) => {
                         console.log(value);
                         console.log(100);
                     }
                 )
            } catch (error) {
                console.log(error);
            }
        })()
        console.log('主线程');
        // 输出:先执行主线程,函数瞬间调用完,将异步函数推进队列,等待调用执行。
        //      主线程
        //      {code: 200, message: "成功!", result: {…}}
        //      100

async / await request succeeded 

as failed

5. Promise advantages

Advantages:
1. The way to specify the callback function is more flexible:
        old: you must specify the promise before starting the asynchronous task
        : start the asynchronous task => return the promise object => bind the callback function to the promise object (you can even specify it after the asynchronous task ends )

2. Support chain calls, which can solve the problem of callback hell
        (1) What is callback hell:
                callback function nested call , the result of asynchronous execution of external callback function is the condition for the execution of nested callback function.

        (2) Disadvantages of callback hell:
                the code is not easy to read, and it is not easy to handle exceptions.

        (3) A not very good solution:
                chain call of then
        (4) Ultimate solution:
                async/await (the bottom layer actually still uses chain call of then)

3. Macro queue and micro queue

1 Overview

The queue used to store callback functions to be executed in JS contains 2 different specific queues:
        macro queue: used to save macro tasks (callbacks) to be executed, such as timer callbacks, DOM event callbacks, and ajax callbacks.

        Micro-queue: used to save micro-tasks (callbacks) to be executed, such as: promise callbacks, MutationObserver callbacks. The only microtasks currently in contact with are Promise callbacks.

        Execution: The JS engine must first execute all initialization synchronization task codes. Every time before the first macro task is ready to be executed, all micro tasks must be taken out and executed one by one, that is, the priority of micro tasks is higher than that of macro tasks. , the macrotask is executed after the microtask is executed , and it has nothing to do with the code position of the microtask.

Reference: JS Asynchronous Macro Queue and Micro Queue - BAHG - 博客园

2. Related interview questions

Macro queue: [Macro task 1, Macro task 2...]
Micro queue: [Micro task 1. Micro task...]
Rule: Before executing a task in the macro queue, first look at the micro Whether there are pending microtasks in the queue.
        1. If there is, execute the microtask first.
        2. If not, execute in sequence according to the sequence of tasks in the macro queue.

2.1 Question Type 1

Microtasks are executed before macrotasks.

        setTimeout(() => {
            console.log('timeout1');
        })
        setTimeout(() => {
            console.log('timeout2');
        });
        Promise.resolve(3).then(
            value => { console.log('成功了1'); }
        )
        Promise.resolve(4).then(
            value => { console.log('成功了2'); }
        )

2.2 Question Type 2

The microtask is called in the macrotask:

Macro task queue: timeout2 after 3s ; timeout1 after 5s then push timeout3 into the macro task , and then push success 5 into the micro task .

Micro task queue: success 3; success 4; success 5

Execution results: microtasks are executed first: success 3; success 4; macrotask execution: timeout2 with an interval of 3 seconds  is executed first, timeout1 with an interval of 5s  is executed again, and then timeout3 is pushed into the macrotask , and success 5 is pushed into the microtask task . The microtask is executed successfully 5 first , and then the macrotask timeout3 is executed.

Note: There may be microtasks placed in the microqueue in the macrotask, and the microtask is executed first at this time.

        setTimeout(() => {
            console.log('timeout1');
            setTimeout(() => {
                console.log('timeout3');
            })
            Promise.resolve(5).then(
                value => { console.log('成功了5'); }
            )
        }, 5000)
        setTimeout(() => {
            console.log('timeout2');
        }, 3000)
        Promise.resolve(3).then(
            value => { console.log('成功了3'); }
        )
        Promise.resolve(4).then(
            value => { console.log('成功了4'); }
        )

2.3 Question type three

    <script>
        setTimeout(() => {
            console.log('0');
        });
        new Promise((resolve, reject) => {
            console.log('1');
            resolve();
        }).then(() => {
            console.log('2');
            new Promise((resolve, reject) => {
                console.log('3');
                resolve();
            }).then(() => {
                console.log('4');
            }).then(() => {
                console.log('5');
            })
        }).then(() => {
            console.log('6');
        })
        new Promise((resolve, reject) => {
            console.log('7');
            resolve();
        }).then(() => {
            console.log('8');
        })
    </script>

 

 

Output: 1 7 2 3 8 4 6 5 0

Guess you like

Origin blog.csdn.net/qq_37308779/article/details/126130378