Hello everyone, I am Lin Yiyi, asynchronous programming in JS is inevitable, but also interview must ask. In this article, asynchronous programming principles are explained in an easy-to-understand language. Get started at 😁

Mind mapping

I. Timer

Timer: Set a timer. When the timer is set, the browser will execute the corresponding method. After each timer is executed, a number is returned. The number of each timer is different.

1. Set the timer

  • setTimeout([function], [interval])

Function is executed after the specified time is reached. And execute it once

let count = 1
let timer = setTimeout(function(){
    count++
    console.log(count)  / / 2
}, 1000)
console.log(timer)  / / 1
Copy the code
  • setInterval([function], [interval])

In the set time to execute, do not actively stop the case has been executed.

let count = 1
let timer = setInterval(function(){
    count++
    console.log(count)  / / 2
}, 1000)
console.log(timer)  / / 1
/* * 2 * 3 * 4 *... * /
Copy the code

2. Clear the timer

ClearTimeout/clearInterval both can clear the above two kinds of timers.

  • How do I clear timers?

You only need to clear the return value number of the timer.

let count = 1
let timer = setInterval(function(){
    count++
    console.log(count)
    // count == 3 ? clearTimeout(timer) : null
    count == 3 ? clearInterval(timer) : null
}, 1000)
Copy the code

Second, the principle of asynchronous programming

Let’s start with a little example

let a = 0
setTimeout(() = >{
    console.log('a', ++a)
}, 0)
console.log(a)
/* Outputs * 0 * 1 */
Copy the code

In the example above, setTimeout is asynchronous. The browser will queue the asynchronous code and wait until the synchronous code completes

1. The synchronous

JS is single-threaded. When the code is executed from top to bottom, the synchronized code needs to be executed before the next task can be carried out. So cycles and things like that

2. The asynchronous

All tasks that need to wait are asynchronous. When asynchronous code is encountered, instead of waiting, the asynchronous task is directly put into the task queue, and the code that is not asynchronous is returned to execute after the subsequent task completes. Such as event binding, all timers, asynchronous processing of Ajax, partial callback functions, browser rendering, etc.

let a = 0
setTimeout(() = >{
    console.log('a', ++a)
}, 0)
console.log(a)
while(true){
}
Copy the code

The code above is in an infinite loop and will not execute even when the timer is up. Because synchronized code does not execute until it has completed one step.

Third, the promise

1. Basic concepts

Promise is just a class that manages asynchronous programming and is itself synchronous. There are three state pending/Promise fulfilled/rejected, only two states appear in three state either success or failure. The executor callback must be passed in when new Promise() or an error is reported. There are two arguments in the callback: resolve, reject.

  • pending: initializes the state and starts executing asynchronous tasks.new Promise(()=>{})“And the promise state will becomepending
  • fulfilled: Indicates that the command is successfulresolve().
  • rejected: Failed and executedrejected().

Let’s start with a little chestnut.

new Promise(() = > {
    setTimeout(() = > {
        console.log(1)},0)
    console.log(2)
}).then()
console.log(3)
/* Outputs * 2 * 3 * 1 */
Copy the code

To create a new Promise instance is new to this process would function to perform first Promise (don’t know the new instance is created in the process of what happened can look at this interview | you have to know the JS prototype and prototype chain). Functions with asynchronous operations will be added to the task queue until the synchronous execution is complete, such as setTimeout function in the function. So the output is 2,3,1.

Let’s look at a little chestnut

const promise = new Promise((resolve, reject) = > {
  resolve('success1')
  reject('error')
  resolve('success2')
})

promise.then((res) = > {
    console.log('then: ', res)
}).catch((err) = > {
    console.log('catch: ', err)
}
// then: success1
Copy the code

The state of promise can only change once. The final state is either a pity or rejected. This means that resolve()/ reject() in the same promise can only be executed once.

How does Promise manage asynchrony

The promise parameter’s callback body accepts two arguments, resolve/ reject, that can be used as two callback functions.

  1. resolve(): If the asynchronous operation is executed successfully, the state of the promise becomesfulfilled, can provide a return value in.then()The first parameter is received
  2. reject(): After the asynchronous operation fails to execute, the state of the promise becomesrejected, can provide a return value in.then()The second parameter is received

Only one argument is passed in resolve() and reject(). Promise status changes and never changes again. Resolve () and reject() are asynchronous operations. Resolve () and reject() are asynchronous operations that execute the resolve/reject code and wait until the main task is empty to execute the stored method. Promise objects have private properties promise.resolve ()/ promise.reject (), etc.

What about a little chestnut that doesn’t make any sense

new Promise((resolve, reject) = > {
    setTimeout(() = > {
        console.log('darling')
        resolve('ok')
        // reject('fail')
        console.log('one')},0)
}).then( res= > {
    console.log('status:', res)
}, res= > {
    console.log('status:', res)
})
/ / Lin
/ / one by one
// ok
Copy the code

Resolve /reject is asynchronous.

3. promise.then(onfulfilled, onrejected) / promise.catch()

  • promise.then(onfulfilled, onrejected)
  1. promise.then()The method has two parameters that correspond to two different states of the Promise,fulfilled, rejected. The corresponding state executes the corresponding method.
  2. promise.then()The argument is a function. If you pass something other than a functionValue through, that is,resolve()/reject()The return value of.then()In receiving.
  3. promise.then()Chaining calls, the reason why chaining calls is not.then()Methods ofreturn thisBut every one of them.then()Method returns a new onePromiseInstance.
  • promise.catch()
  1. promise.catch()promise.then()Shorthand for the second parameter, which is used to capturereject()After the executionrejectedState.
  2. .catch()It is also possible to implement chain calls, causes and.then()The same method returns a new onepromise.

.then()/.catch()None of the return values inpromiseIts own instance, because it creates an endless loop

Warm up the topic

1. Give me a small chestnut

Promise.resolve(1)
    .then((res) = > {
        console.log(res)
        return 2
    }).catch(err= > {
        console.log(err)
    }).then( res= > {
        console.log(res)
    })
/ / 1. 2
Copy the code

The final output is 1, 2,

2. Pick a small chestnut with a value of penetration

Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)

/ / equivalent to the
// Promise.resolve(1)
// .then(console.log)
Copy the code

3. Then ()/.catch() does not return its own promise instance

let pro = Promise.resolve()
  .then(() = > {
    console.log('promise', pro)
    return pro
  })
// Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
Copy the code

The created Promise instance is Pro, and the return value cannot be Pro, otherwise it will cause an endless loop.

4. About Promise. The catch ()

Let’s start with an interview question

new Promise((resolve, reject) = > {
    reject(1)
}).catch(() = > {
    console.log(2)
// throw 'err'
}).then(() = > console.log(3), (v) = > console.log(v))

// Output: 2, 3
Copy the code

I don’t know if you got that right

  • Catch is indeed the syntactic sugar for the second argument to.then. It is worth mentioning in the.catchInternally if no error or a false promise is raisedreject()The result value returned by.catch isresolve()All will be displayed as successful. Output The second output is 3.

5. Promise.all([promise1, promise2…] )

Promise.all() waits for all the Promise states in the argument to succeed before executing the callback. Then (), and.catch() if one of them fails. The arguments received are an array of Promise instances, and the.all() method returns a new Promise instance.

  • All callbacks were successfully executed.then()You get an array
  • If any of them fail to executepromiseState, callback.catchWill catch an execution failurepromise.
  • A failed promise causes the promise.all method to stop execution immediately.
var p1 = Promise.resolve(1)
var p2 = Promise.resolve(2)
var p3 = Promise.resolve(3)
let pro =  Promise.all([p1, p2, p3])
  .then(res= > {
      console.log(res)  //  [1, 2, 3]
  })
  .catch( err= > {
      console.log(err)
  })
console.log(pro)    // Promise {<pending>}
Copy the code

Then () returns an array of the return values of resolve().

6. Promise.race()

.race() also receives a set of asynchronous tasks and executes them in parallel, keeping only the results of the fastest completed asynchronous operation. The other methods are still running, but the results are discarded.

  • It receives an array and only gets the fastest oneresolve()/rejected()Is not an array
var p1 = new Promise(function(resolve, reject) {
    setTimeout(reject, 500."one");
});
var p2 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 100."two");
});

Promise.race([p1, p2]).then(function(value) {
  console.log(value); // "two"
});
Copy the code

Both are done, but P2 is faster

7. Promise.finally()

The.finally method also returns a Promise, and when the Promise ends, the callback will be executed, whether resolved or Rejected.

let promise = new Promise((resolve, reject) = > {
    reject('error')
}).then( res= > {
    console.log('then', res)
    return res
}).catch( err= > {
    console.log('catch', err)   // `catch error`
     return err
}).finally( () = > {
    console.log('finally')  //'finally'
})
Copy the code

Warm up the topic

Warm up the topic 1

const promise = new Promise((resolve, reject) = > {
  console.log(1)
  resolve()
  console.log(2)
})
promise.then(() = > {
  console.log(3)})console.log(4)
// 1, 2, 4, 3
Copy the code

This is a big pity. Because resolve() is asynchronous, promise.then is also asynchronous, and will not be fulfilled until the fulfilled state of resolve() is fulfilled.

Warm-up questions 2

const promise = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    console.log('once')
    resolve('success')},1000)})const start = Date.now()
promise.then((res) = > {
  console.log(res, Date.now() - start)
})
promise.then((res) = > {
  console.log(res, Date.now() - start)
})
/* Once * success 1002 * SUCCESS 1002 */
Copy the code

Promise.then () even if there are more than one, the resolve()/reject() calls are executed simultaneously. So success 1002 is also printed

Warm up 3

const p = function(){
    return new Promise((resolve, reject) = >{
        const p1 = new Promise((resolve, reject) = > {
            setTimeout(() = >{
                resolve(1)},0)
            resolve(2)
        })
        p1.then((res) = >{
            console.log(res)
        })
        console.log(3)
        resolve(4)
    })
}
p().then(res= > {
    console.log(res)
})
console.log('end')
// 3, end, 2, 4
Copy the code

Resolve (2); resolve(4)·; The result of resolve(1) ‘will not be executed because the Promise state has changed.

Async and await

Let’s start with a chestnut

function fn(){
    return new Promise((resolve, reject) = > {
        setTimeout( () = > {
            Math.random() < 0.5 ? resolve('resolve 001') : reject('reject 002')},0)})}async function get() {
    let res = await fn()
    console.log(res)
    console.log(1212)
}
get()
Copy the code

1. async

  1. asyncawaitIt was added in ES7promiseThe way to do this is with the syntax sugar provided by the ES7 series,awaitIt cannot be used alone but must be combinedasyncTo use.
  2. asyncWill return apromiseObject,asyncFunction calls do not block code

2. await

  1. awaitIs used toWait to getapromiseresolve/rejectThe result of the execution, as abovelet res = await fn()Is the firstfn()After execution, to obtainresolve/rejectReturns the result, howeverawaitYou don’t have to follow onepromiseBut it doesn’t make sense.
  2. Await or await fn ()This operation is not synchronous, but asynchronous.awaitThe following code does not execute, but moves to the task queue waiting area until other tasks in the main stack complete andfn()In thepromiseReturn the result,awaitThe following code can then be executed back on the main stack.awaitYou can makepromiseIs more like synchronized code.
  3. ifawaitWaiting for thePromiseReturn value if yesrejected/peding.awaitNone of the following code will execute,reject()The returned representative has reported an error. Remember that await 10 is equivalent to await promise.resolve (10)

To give an example, async/await is syntactic sugar

async function async1() {
	console.log('async1 start');
	await async2();
	console.log('async1 end');
}
// The above code is equivalent to ==>
async function async1() {
    console.log('async1 start');
    Promise.resolve(async2()).then(() = > {
        console.log('async1 end')})}Copy the code

thinking

Warm-up 1, is await synchronous? And find the output result

console.log(1)
function fn(){
    return new Promise((resolve, reject) = > {
        console.log(5)
        resolve('resolve 001')
        console.log(6)})}async function get() {
    console.log(2)
    let res = await fn()
    console.log(res)
    console.log(3)
}
get()
console.log(4)
//1, 2, 5, 6, 4, resolve 001, 3
Copy the code

After fn() is executed, the thread will begin to relinquish. Then the code below the “await” will not execute immediately and will go to the waiting area of the main stack. After console.log(4) is executed in the main stack, the code at the “await” will be executed.

2. Warm-up 2, find the output result

console.log(1)
async function get() {
    console.log(2)
    let res = await 200
    console.log(res)
    console.log(3)
}
get()
console.log(4)
// 1, 2, 4, 200, 3
Copy the code

A. await b. await C. await D. await It also states that await can be followed by a non-promise instance.

3. Warm up and find the output

async function fn(){
    await fo() // Promise.resolve(fo()) ==> undefined
    console.log(1)}async function fo(){
}
fn()
/ / 1
Copy the code

The output is 1 because fo() has a return value, which is not reject()

4. Warm up and find the output

async function async1() {
  console.log('async1 start')
  await new Promise(resolve= > {
    console.log('promise1')})console.log('async1 success')
  return 'async1 end'
}
console.log('srcipt start')
async1().then(res= > console.log(res))
console.log('srcipt end')  
// srcipt start, async1 start, promise1, srcipt end,
Copy the code

Async1 success is not output above because the Promise instance returned by await is still pending and no result is returned so the following code will not execute. Async1 returns a Promise and does not print async1 end

4. Classic interview questions

1. Advantages and disadvantages of Promises/Why use promises?

  • Pros: Promise solves callback hell, promise greatly enhances the readability and maintainability of nested functions,
  • Cons: Promise can’t be cancelled, errors need to be caught with callback functions; If no callback function is set, errors thrown from within a Promise are not reflected externally. When you are in the pending state, you cannot tell what stage of progress you are at, whether you have just started or are about to complete

2. Differences between setTimeout, Promise, Async/Await

  • SetTimeout: The setTimeout callback is placed in the macro task queue until the execution stack is empty
  • Promise: Promise itself is a synchronous execute now function. When resolve or reject is executed in executor, then/catch is executed asynchronously. When the main stack is complete, The resolve/reject method is called.
  • Async: An async function returns a Promise object. When the function executes, it will return an await and wait until the async operation is completed before executing the following statement in the function body. It can be understood as giving up the thread, out of the async function body.

3. Implementing a sleep function, such as sleep(1000) means waiting for 1000 milliseconds.

function sleep1(time) {
    return new Promise(resolve= > {
        setTimeout(() = > {
            resolve();
        }, time);
    })
}
sleep1(1000).then(() = > console.log("sleep1"));
Copy the code

4. If the Promise constructor executes synchronously or asynchronously, what about the then method

Promise is synchronous; the callback function is executed immediately when new Promise (callback) is executed, and the then() method is asynchronous.

const promise = new Promise((resolve, reject) = > {
    console.log(1)
    resolve()
    console.log(2)
})
promise.then(() = > {
    console.log(3)})console.log(4)
Copy the code

1243, the Promise constructor is executed synchronously and the THEN method asynchronously

5. Introduce the use, principle and error handling of Promise.all

const p = Promise.all([p1, p2, p3]);
Copy the code

The promise. all method takes an array of parameters. P1, P2, and p3 are all Promise instances. (The promise. all method can take arguments that are not arrays, but must have an Iterator interface and return each member as a Promise instance.)

5. Introduce the difference between promise.all, promise.race ()

Look at the introduction above

The various API implementations of Promise will be implemented in the next article. Give a look 😂

Five, the reference

I Promise I will (10 questions)

Classic INTERVIEW Questions: The most detailed handwritten Promise tutorial ever

MDN async/await

Sixth, the end

Thank you for reading here, if the article can enlighten or help you a little welcomegithub starThis is Lin Yiyi. See you next time.