The current mainstream JavaScript environment executes code in a single-threaded mode. JavaScript is a scripting language running on the browser side. In order to realize the dynamic interaction of the page, the core of realizing the interaction of the page is DOM operation. If different threads perform different operations on the DOM at the same time, for example, one thread adds the DOM and another thread deletes the DOM, the browser will not know how to deal with it. In order to avoid this situation, js can only be executed in order from top to bottom, which is a synchronous task. The single-threaded JavaScript language cannot handle a large number of time-consuming tasks simultaneously, which requires asynchronous coding.

Synchronous mode and asynchronous mode

Synchronous mode

Synchronous mode is where the tasks in the code are executed in sequence, and the later task must wait until the previous one has completed

console.log('global begin') function bar () { console.log('bar task') } function foo () { console.log('foo task') bar() } foo() console.log('global end') // Output global begin foo task bar Task global endCopy the code

Asynchronous mode

Asynchronous mode: do not wait for the end of the task to start the next task, for time-consuming operations are started immediately after the next task, the subsequent logic is generally defined through the callback function. Helps the single-threaded JS language handle a large number of time-consuming tasks simultaneously. Cons: Code execution order is out of order

console.log('global begin') setTimeout(function timer1 () { console.log('timer1 invoke') }, 1800) setTimeout(function timer2 () { console.log('timer2 invoke') setTimeout(function inner () { console.log('inner invoke') }, 1000) }, 1000) console.log('global End ') global Begin Global end timer2 invoke Timer1 invoke inner invokeCopy the code

Callbacks — the foundation of all asynchronous programming schemes

Callback function: a function defined by the caller and handed to the executor to execute

Function foo(callback){setTimeOut(fucntion(){callback()},1000)} foo(function(){console.log(' this is a callback function ') Console. log(' the caller tells the caller what to do when the asynchronous task is over ')})Copy the code

Promise

A promise is a class that needs to be executed with an executor, which executes immediately

Promise objects represent future events that are used to deliver messages for asynchronous operations.

Promise Object Features

1, the state of the object is not affected by the outside world. **Promise objects represent an asynchronous operation with three states:

  • Pending: The initial state, not the success or failure state.
  • Fulfilled: indicates that the operation is completed successfully.
  • Rejected: Indicates that the operation fails.

Only the result of an asynchronous operation can determine the current state, which cannot be changed by any other operation.

** once the state changes, it will not change, any time you can get this result. ** The state of a Promise object can change from Pending to Resolved and from Pending to Rejected. So as long as these two things happen, it’s frozen, it’s not going to change anymore, it’s going to stay that way.

Use case for PROMISE

Return new Promise(function(resolve,reject){var XHR = new XMLHttpRequest() xhr.open('GET',url) xhr.responseType = 'json' xhr.onload = function(){ if(this.status==200){ resolve(this.response) }else{ reject(new Error(this.statusText)) } } xhr.send() }) } ajax('/api/user.json').then(function(res){ Console.log (res)},function(err){console.log(err)}) /* then The then method is defined in the prototype object. The then method can be called multiple times under the same promise object, so then returns a new promise object. The then method can be called chained, If a Promise is returned, then the callback to the then method waits for it to finish. The arguments in the then() should be functions. If it's not a function, ignore it. */ promise.resolve (1).then(2).then(promise.resolve (3)).then(console.logCopy the code

Promise chain calls

function ajax(url){ return new Promise(function(resolve,reject){ var xhr = new XMLHttpRequest() xhr.open('GET',url) xhr.responseType = 'json' xhr.onload = function(){ if(this.status==200){ resolve(this.response) }else{ reject(new Error(this.statusText)) } } xhr.send() }) } ajax('/api/user.json').then(function(res){ console.log(111) return ajax('/api/user.json') }).then(function(res){ console.log(222) console.log(res) return ajax('/api/user.json') }).then(function(res){ console.log(333) return ajax('/api/user.json') }).then(function(res){ console.log(444) return Then (function(res){console.log(555) console.log(res)}) // Output information 111 222 {users:'/api/users.json',posts:'/api/users.json'} 333 444 555 fooCopy the code

The THEN method on the Promise object returns an entirely new Promise object

The subsequent THEN method registers the callback for the Promise returned by the previous THEN

The return value of the callback function in the previous THEN method is taken as an argument to the later THEN method callback

Promise static methods

Promise.resolve

Promise.resolve('foo').then(function (value) {console.log(value)}) = new Promise(function (resolve, Reject) {resolve('foo')}); reject) {resolve('foo')}); Var Promise = ajax('/ API /users.json') var promise.resolve (Promise) console.log(Promise) === = promise2) // If the object is passed with the same then method as the Promise, // promise.resolve ({then: function (onFulfilled, onRejected) { onFulfilled('foo') } }).then(function (value) {console.log(value)})Copy the code

Promise.reject

Promise.reject('anything').catch(function (error) {console.log(error)})Copy the code

Promise.all- Wait for all tasks to finish

When multiple promises are executed synchronously, they end successfully only when all of them are successfully executed. If one promise fails, it ends in failure

var promise = Promise.all([
    ajax('/api/users.json'),
    ajax('/api/posts.json')
])
promise.then(function (values) {
    console.log(values)
}).catch(function (error) {
    console.log(error)
})
Copy the code

Promise.race- only waits for the first finished task

// promise.race const request = ajax('/ API /posts.json') const timeout = new Promise((resolve, reject) => { setTimeout(() => reject(new Error('timeout')), 500) }) Promise.race([ request, timeout ]).then(value => { console.log(value) }).catch(error => { console.log(error) })Copy the code

Promise execution timing

Console. log('global start') console.log('global start') console.log('global start') SetTimeout (() => {console.log('setTimeout')}, 0) // Promise's callback is a microtask, Direct execution at the end of the call Promise. Resolve (). Then (() = > {the console. The log (' Promise ')}), then (() = > {the console. The log (' Promise 2 ')}), then (() = > {console.log('promise 3')}) console.log('global end') // Output global start Global end Promise 2 promise 3 setTimeoutCopy the code

The vast majority of asynchronous calls today are executed as macro tasks, but promises, MutationObserver, and Process. nextTick are executed as microtasks.

Generator

A Generator is a function that declares a Generator object with * and executes the function by calling.next(). The function can return a value internally by using yield. The value is retrieved in the next method return object, which also contains a done property indicating whether the generator is finished. If you pass an argument to the next method, it is returned as a yield statement value. If the throw method is called from outside, it also causes the generator function to execute down to throw an exception.

function * foo () { console.log('start') const res = yield 'foo' console.log(res) } const generator = foo() const result Next () console.log(result) generator.next('bar') // Output start {value:'foo',done:false} bar function * foo () { console.log('start') try { const res = yield 'foo' console.log(res) } catch (e) { console.log(e) } } const generator = Foo () const result = generator.next() console.log(result) generator.throw(new Error(' generator Error ')) // Output start {value:'foo',done:false} Error:Generator errorCopy the code

Async Await

async function main () {
    try {
        const users = await ajax('/api/users.json')
        console.log(users)
        const posts = await ajax('/api/posts.json')
        console.log(posts)
        const urls = await ajax('/api/urls.json')
        console.log(urls)
    } catch (e) {
        console.log(e)
    }
}
const promise = main()
promise.then(() => { console.log('all completed') })
Copy the code

What do eventLoops and message queues do?

EventLoop is responsible for listening to the call stack and the message queue. Once all tasks on the call stack are finished, the EventLoop takes the first callback function from the message queue and adds it to the message queue.

Message queues are used to process asynchronous tasks. Whenever an asynchronous invocation event occurs, it will be queued. After execution, the main thread will be notified by the task queue and the JS engine will take over the event.

What is a macro task? What is a microtask?

Tasks in the callback queue are macro tasks, and all events (sync blocks, setTimeout, setInterval, etc.) are macro tasks. Microtasks are tasks that are executed immediately after the end of the current task, including Promise, MutationObserver, and Process. nextTick. In order, synchronous events have the highest priority and these asynchronous events have the second highest priority. When a Promise is encountered while executing a macro task, a microtask (callback in.then()) is created and added to the end of the microtask queue.