– introduction

We need to understand the JS operating mechanism, macro tasks, micro tasks and what are the differences and common interviews may be asked about setInterval macro tasks and micro tasks pomis.then method specific implementation.

– JS running mechanism

1. Js is single-threaded execution

Js is single threaded which means the JS engine thread

In the browser environment, there are JS engine threads and rendering threads, and the two threads are mutually exclusive.

In a Node environment, there are only JS threads.

2. The host

The environment in which js runs. Usually a browser or node

3. The execution stack

Is a stack structure for storing calls, following the principle of first in, last out.

function foo(){
	throw new Error('I am error')}function bar(){
	foo()
}
bar()
Copy the code

When we start executing our JS code, we first execute a mian function and then execute our code. Based on the principle of “first in, last out”, functions that are executed later are popped off the stack. We can also see in the figure that foo is executed later and popped off the stack when we are finished executing.

4. Event Loop

How does JS actually work?

In the Event loop, each loop is called a TICK and performs the following tasks:

  • The execution stack selects the first macro task (usually script) to be queued and executes the synchronized code until the end;
  • Check whether there are microtasks, if there are, it will execute until the microtask queue is empty;
  • If hosted by a browser, pages may be rendered
  • Start the next tick and execute the asynchronous code in the macro task (setTimeout callback etc)
5. Micro and macro tasks

Finally, we come to the protagonist of today’s talk. First of all, let’s talk about the difference between the two:

Macro tasks are initiated by Node or the browser, while micro tasks are initiated by the JS engine

Specific events of macro tasks include script (which can be understood as outer synchronization code), setTimeout/setInterval, UI events, I/O streams, etc.

Microtasks have promise. Then methods (note that the code inside new Primes() is not microtasks),.catch-finally methods, etc.

The second order of execution is: main thread > micro task > macro task. 【 Popular memory method: Start small first 】

We’ll start with an appetizer

consle.log(111)/ / main thread

setTimeout(() = >{
    console.log(222)/ / macro task
})

new Promise((resovle) = >{
    resovle()
    console.log(333)/ / main thread
    // Note that the code inside the new Promise() object is the main thread code and.then().catch().then() is the microtask
}).then(() = >{
    console.log(444)Micro / / task
}).findally(() = >{
    console.log(555)Micro / / task
})

console.log(Awesome!)/ / main thread

// Print order :111 333 666 444 555 111
Copy the code

Find the question of the day: both macro and micro tasks can operate asynchronously, what is the problem to be solved by micro tasks?

Answer: In order to solve the problem of waiting too long for asynchronous callback when the main thread has too many tasks, an effective tradeoff between real-time and efficiency can be made.

– Implement setInterval() with macro task setTimeout()

SetTimeout () : Executes only once for the specified number of milliseconds

SetInterval () : Calls functions or expresses computations at the same interval. The method is executed until clearInterval is called or the window is closed.

The idea is to use a recursive function, setTimeout constantly to achieve the effect of setInterval.

function mySetInterval(fn,ms){
	function interval(){
		setTimeout(interval,ms)// call interval() every ms milliseconds
		fn();
	}
	setTimeout(interval,ms)// Execute interval() for the first time in ms milliseconds
}
Copy the code

The above setTimeout execution process forms a closure, which can be improved to increase the number of executions by one

function mySetInterval(fn, ms,count){
  function interval(){
    if(typeof count==='undefined'||count-->0) {setTimeout(interval, ms);
      try{
        fn()
      }catch(e){
        count = 0;
        throwe.toString(); }}}setTimeout(interval, ms)
}
Copy the code

– Handwritten microtask Promise.then ()

The implementation of the. Then () method is indispensable to the interview when the promise question is asked

  • Save current state
  • Store the value of resolve
  • Use the callback to the. Then function and pass the parameter to the. Then function

Before you start writing these three steps, understand the basic form of a Promise

// The basic form of the promise object

new Promise((resolve, reject) = > {

    resolve('ok')
    
}).then(res= > {

    console.log(res);
    //output: ok
    
    return Promise.resolve(res)
    
}).then(res= > {

    console.log(res);
    //output: ok
    
})
Copy the code

The first step is to look at the basic Promise form. In the beginning, a Promise receives a callback, executes it, and passes resovle() and reject() inside.

function myPromise(fn) {
    this.state = PENDING// Any myPromise object defaults to pending
    this.value = null

    function resolve(value) {
            this.value = value// Save the parameter
    }

    function reject(value) {
            this.value = value// Save the parameter}}try {
        fn(resolve, reject)	// The callback function executes
    } catch(error) {
        reject(error)
    }
}
Copy the code

Second, to be able to.then() we need to mount the.then method on the myPromise prototype, which needs to be executed by resovle(‘ OK ‘), as well as the resovle inside the.then() method. This requires setting up three states and saving the callback function. .then() executes the stored callback function as long as a myPromise object was previously returned

// We need to set up three states
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'

function myPromise(fn) {
    this.state = PENDING
    this.value = null
    this.resolvedCallbacks = []// Array of resolve callback (.then() first callback)
    this.rejectedCallbacks = []Reject (.then(), the second callback)

    function resolve(value) {
        if (this.state === PENDING) {
        // In its basic form, the Promise object is a new object. Then the resolve method returns a value.
        // Return a Promise object to return a Promise object
            this.state = RESOLVED// Change the status to Resolved
            this.value = value
            this.resolvedCallbacks.map(cb= > cb(value))// Execute the resovle callback stored in resolvedCallbacks}}function reject(value) {
        if (this.state === PENDING) {// Change the status to the Rejected state
            this.state = REJECTED
            this.value = value
            this.rejectedCallbacks.map(cb= > cb(value))// Execute the rejecte callback stored in resolvedCallbacks}}try {
        fn(resolve, reject)	/ / implementation
    } catch(error) {
        reject(error)	//
    }
    
    // Mount method
    myPromise.prototype.then = function(onFulfilled, onRejected) {
        const that = this
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v= > v
        Resovle = resovle; resovle = resovle; resovle = resovle
        onRejected = typeof onRejected === 'function' ? onRejected : err= > err
        Reject (reject); reject (reject); reject (reject)
        if (that.state === PENDING) {// The first state is pending
            that.resolvedCallbacks.push(onFulfilled)// store the resovle callback
            that.rejectedCallbacks.push(onRejected)// store the reject callback
        }
        if (that.state === RESOLVED) {
        onFulfilled(that.value)
        }
        if (that.state === REJECTED) {
            onRejected(that.value)
        }
        
    }
    
}

Copy the code

A simple promise.then () method is implemented.

Ps: Good article recommendation

Js Macro and Micro Tasks – Wangziye – Blogpark (cnblogs.com)