reference
Event Loop Execution sequence
- The entire script is initially executed as a macro task
- During the execution, the synchronized code is executed directly, the macro task enters the macro task queue, and the micro task enters the micro task queue
- Check the list of micro tasks after the current macro task is executed, and execute them successively until all the tasks are executed
- Performs rendering of the browser UI thread
- Check whether there are Web Worker tasks and execute them
- After executing the macro task of this round, return to 2 and repeat until the macro and microtask queues are empty
1. I Promise
1. promise
const promise1 = new Promise((resolve, reject) = > {
console.log('promise1')})console.log('1', promise1);
Copy the code
When a new Promise is encountered, promise1 in the constructor is executed, and synchronization code 1 is executed. Promise1 is not resolved or rejected, so the state is still pending
// ans
'promise1'
'1' Promise{<pending>}
Copy the code
2. promise resolve then
const promise = new Promise((resolve, reject) = > {
console.log(1);
resolve('success')
console.log(2);
});
promise.then(() = > {
console.log(3);
});
console.log(4);
Copy the code
- To meet a
new promise
Execute the synchronization code1
- In case of
resolve(success)
That will bepromise
Status is changed toresolved
And save the value - Continue to execute the synchronization code
2
- Jump out of the
promise
Encountered,promise.then
Microtask, join the microtask queue - Execute sync code
4
- This round of macro tasks are all executed, check the micro tasks, and find
promise.then
The microtask state is zeropending
, the execution.
// ans
1 2 4 3
Copy the code
3. promise then
const promise = new Promise((resolve, reject) = > {
console.log(1);
console.log(2);
});
promise.then(() = > {
console.log(3);
});
console.log(4);
Copy the code
- Similar to problem two, except in
promise
There is nothing in theresolve
orreject
- so
promise.then
It does not execute, it only executes after the state has been changed.
// ans
1 2 4
Copy the code
4. promise resove then res
const promise1 = new Promise((resolve, reject) = > {
console.log('promise1')
resolve('resolve1')})const promise2 = promise1.then(res= > {
console.log(res)
})
console.log('1', promise1);
console.log('2', promise2);
Copy the code
-
From top to bottom, a new Promise is encountered and the code promise1 in the constructor is implemented
-
When the resolve function is encountered, change the state of promise1 to Resolved and save the result
-
When it encounters the promise1. Then microtask, place it on the microtask queue
Promise2 is a new Promise whose state is' pending 'Copy the code
-
Execute synchronization code 1 and print the promise1 state as Resolved
-
Execute synchronization code 2 and print the status of promise2 as pending
-
When the macro task is complete, look for the task queue and find the promise1. Then task that is resolved and execute it.
// ans
'promise1'
'1' Promise{<resolved>: 'resolve1'}
'2' Promise{<pending>}
'resolve1'
Copy the code
5. fn promise res
const fn = () = > (new Promise((resolve, reject) = > {
console.log(1);
resolve('success')
}))
fn().then(res= > { // fn is called before start
console.log(res)
})
console.log('start')
Copy the code
The fn function returns a new Promise directly, and the fn function is called before start, so its contents should be executed first.
// ans
1
'start'
'success'
Copy the code
6. fn promise res2
const fn = () = >
new Promise((resolve, reject) = > {
console.log(1);
resolve("success");
});
console.log("start");
fn().then(res= > { // fn calls are executed after start
console.log(res);
});
Copy the code
Start is printed before 1
// ans
"start"
1
"success"
Copy the code
2. Promise combined with setTimeout
1. promise setTimeout resolve
console.log('start')
setTimeout(() = > { // The macro task is placed in the next macro task queue
console.log('time')})Promise.resolve().then(() = > {
console.log('resolve')})console.log('end')
Copy the code
-
The entire script is initially executed as a macro task, and the synchronized code is pushed directly onto the stack for execution, so start and end are printed first.
-
SetTimout is put into the macro task queue as a macro task (next)
-
Promise.then is put into the microtask queue as a microtask
-
When the macro task is complete, check the microtask, find promise.then, and execute it
-
Next, the next macro task, setTimeout, is found and executed.
// ans
'start'
'end'
'resolve'
'time'
Copy the code
2. promise setTimeout
const promise = new Promise((resolve, reject) = > { console.log(1); setTimeout(() = > { console.log("timerStart"); resolve("success"); console.log("timerEnd"); }, 0); console.log(2); }); promise.then((res) = > { console.log(res); });console.log(4);
Copy the code
Similar to 3.2, resolve has a setTimeout timer layer.
- From top to bottom, encounter first
new Promise
Executes the code in the constructor1
- The timer is then encountered and the function in that timer is placed in the delay queue for the next macro task
- Execute sync code
2
- Jump out of the
promise
Function, encounteredpromise.then
But its state is still zeropending
, it is understood that it is not executed first - Execute sync code
4
- After a round of the loop, the second macro task is entered and the delay queue is found
setTimeout
Timer, execute it - Executed first
timerStart
“And then metresolve
That will bepromise
Change the state ofresolved
And save the result and put the previouspromise.then
Push into the microtask queue - Continue to execute the synchronization code
timerEnd
- The macro tasks are all executed, and the microtask queue is searched
promise.then
This microtask, execute it.
// ans
1
2
4
"timerStart"
"timerEnd"
"success"
Copy the code
3. (1) setTimeout
setTimeout(() = > {
console.log('timer1');
setTimeout(() = > {
console.log('timer3')},0)},0)
setTimeout(() = > {
console.log('timer2')},0)
console.log('start')
Copy the code
// ans
'start'
'timer1'
'timer2'
'timer3'
Copy the code
3. (2) setTimeout promise
setTimeout(() = > {
console.log('timer1');
Promise.resolve().then(() = > {
console.log('promise')})},0)
setTimeout(() = > {
console.log('timer2')},0)
console.log('start')
Copy the code
// ans
'start'
'timer1'
'promise'
'timer2'
Copy the code
Promise.then is the micro task, which will be added to the list of micro tasks in this round, and timer timer3 is the macro task, which will be added to the next round of macro tasks.
4. Promise. resolve setTimeout nested
Promise.resolve().then(() = > {
console.log('promise1'); / / 2
const timer2 = setTimeout(() = > {
console.log('timer2') / / 5
}, 0)});const timer1 = setTimeout(() = > {
console.log('timer1') / / 3
Promise.resolve().then(() = > {
console.log('promise2') / / 4})},0)
console.log('start'); / / 1
Copy the code
The timer is executed in the promise and the promise is executed in the timer;
Note that the Promise is directly resolve, whereas the previous New Promise is different.
Process analysis:
-
Initially the entire script is executed as the first macro task, which we mark as macro 1 and execute from top to bottom
-
When the promise.resolve ().then microtask is encountered, add the contents of that then to the first microtask queue as 1
-
When the timer timer1 is encountered, add it to the delay list for the next macro task, mark it as macro 2, and wait for execution (regardless of what is inside).
-
Execute the synchronization code start in macro 1
-
After the first macro task (macro 1) is executed, the first microtask queue (micro 1) is checked and there is a promise. Then the microtask needs to be executed
-
Perform print out the synchronization code promise1 in micro 1, then find timer Timer2, add it to macro 2 and mark it as macro 3
-
After the first microtask queue (micro1) is completed, the second macro task (macro2) is executed, starting with the synchronization code timer1
-
Then it encounters the promise2 microtask and adds it to the loop’s queue of microtasks marked as micro 2
-
There is no synchronization code to execute in macro 2, look for the loop microtask queue (micro 2), find promise2, execute it
-
After the second round of execution, macro 3 is executed and Timer2 is printed
// ans
'start'
'promise1'
'timer1'
'promise2'
'timer2'
Copy the code
5. promise pending setTimeout
const promise1 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('success')},1000)})const promise2 = promise1.then(() = > {
throw new Error('error!!! ')})console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() = > {
console.log('promise1', promise1)
console.log('promise2', promise2)
}, 2000)
Copy the code
Process analysis:
- Top to bottom, execute the first one first
new Promise
The function ofsetTimeout
Add it to the next macro task list - Jump out of the
new Promise
Met,promise1.then
This microtask, but its state is still zeropending
, it is understood that it is not executed first promise2
Is a new state for thetapending
thePromise
- Execute sync code
console.log('promise1')
, and printed outpromise1
The status ofpending
- Execute sync code
console.log('promise2')
, and printed outpromise2
The status ofpending
- When you hit the second timer, place it on the next macro task list
- The first macro task completes and no microtasks need to be executed. Therefore, the second macro task is executed
- Execute the contents of the first timer first
promise1
Change the state ofresolved
And save the result and put the previouspromise1.then
Push into the microtask queue - The timer has no other synchronization code to execute, so it executes the microtask queue of this round, i.e
promise1.then
, it throws an error and willpromise2
Is set torejected
- After the first timer is executed, the contents of the second timer are executed
- Print out the
'promise1'
And at this timepromise1
The status ofresolved
- Print out the
'promise2'
And at this timepromise2
The status ofrejected
// ans
'promise1' Promise{<pending>}
'promise2' Promise{<pending>}
test5.html:102 Uncaught (in promise) Error: error!!! at test.html:102
'promise1' Promise{<resolved>: "success"}
'promise2' Promise{<rejected>: Error: error!!! }Copy the code
6.
const promise1 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve("success");
console.log("timer1");
}, 1000);
console.log("What's in promise1?");
});
const promise2 = promise1.then(() = > {
throw new Error("error!!!");
});
console.log("promise1", promise1);
console.log("promise2", promise2);
setTimeout(() = > {
console.log("timer2");
console.log("promise1", promise1);
console.log("promise2", promise2);
}, 2000);
Copy the code
// ans
"What's in promise1?"
"promise1" Promise<pending>
"promise2" Promise<pending>
"timer1"
test5.html:102 Uncaught (in promise) Error: error!!! at test.html:102
"timer2"
"promise1" Promise[<resolved>:"success"]
"promise2" Promise[<rejected>: Error:error!!! ]Copy the code
Small summary 1
-
Once a Promise status changes, it cannot be changed. (see 3.1)
-
.then and.catch both return a new Promise. (As evidenced by 👆1.4 above)
-
A catch catches errors that have not been caught by the upper layer, regardless of where it is connected. (see 3.2)
-
In a Promise, any return value that is not a Promise is wrapped as a Promise object, for example return 2 is wrapped as return promise.resolve (2).
-
A Promise’s.then or.catch can be called multiple times, but if the internal state of the Promise changes and a value is given, that value will be returned each time a.then or.catch is called. (see 3.5)
-
.then or. Catch returns an error object that does not throw an error, so it will not be caught by subsequent.catches. (see 3.6)
-
The value returned by. Then or. Catch cannot be the promise itself, otherwise an infinite loop will occur. (see 3.7)
-
The parameters of.then or.catch are expected to be functions, and pass-through occurs when passing non-functions. (see 3.8)
-
The. Then method takes two arguments, the first for the successful function and the second for the failed function. At some point you can think of catch as a shorthand for the second argument. (see 3.9)
-
The.finally method also returns a Promise, and when the Promise ends, the callback will be executed, whether resolved or Rejected.
3. then catch finally
1. Multiple resolve and reject
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);
})
Copy the code
// ans
"then: success1"
Copy the code
The resolve or reject constructor is valid only on the first execution; multiple calls do nothing. Confirming the first conclusion, once a Promise’s state changes, it cannot be changed.
2. Catch Catches errors that are not caught by the upper layer
const promise = new Promise((resolve, reject) = > {
reject("error");
resolve("success2");
});
promise
.then(res= > {
console.log("then1: ", res);
}).then(res= > {
console.log("then2: ", res);
}).catch(err= > {
console.log("catch: ", err);
}).then(res= > {
console.log("then3: ", res);
})
Copy the code
// ans
"catch: " "error"
"then3: " undefined
Copy the code
Proving the third conclusion, a catch can catch an error that has not been caught by the upper layer no matter where it is connected.
Then3 is also executed because catch() also returns a Promise, and since the Promise returns no value, it prints undefined.
3. Promise chain call
Promise.resolve(1)
.then(res= >{
console.log(res)
return 2
})
.catch(err= > {
return 3
})
.then(res= > {
console.log(res)
})
Copy the code
// ans
1
2
Copy the code
A Promise can be called chained, but a Promise returns a new Promise each time it is called. Then or. Catch.
The output above prints 1 and 2 because resolve(1) is followed by the first THEN method, not the catch method, so the res in the second THEN actually returns the value of the first THEN.
And return 2 is wrapped as resolve(2).
(1) Reject (1) reject(2)
Promise.reject(1)
.then(res= > {
console.log(res)
return 2
})
.catch(err= > {
console.log(err)
return 3
})
.then(res= > {
console.log(res)
})
Copy the code
// ans
1
3
Copy the code
Reject (1) is a catch, and the res in the second THEN returns the catch.
5. The Promise constructor is executed only once
const promise = new Promise((resolve, reject) = > {
setTimeout(() = > {
console.log('timer')
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)
})
Copy the code
// ans
'timer'
'success' 1001
'success' 1002
Copy the code
Of course, if you’re fast enough, it could be 1001 for both.
A Promise’s.then or.catch can be called multiple times, but here the Promise constructor is executed only once.
Or once the internal state of a promise changes and it has a value, each subsequent call to.then or.catch will get that value directly.
6. Throw an error
Promise.resolve().then(() = > {
return new Error('error!!! ')
}).then(res= > {
console.log("then: ", res)
}).catch(err= > {
console.log("catch: ", err)
})
Copy the code
// ans"then: " "Error: error!!!"
Copy the code
Return any non-promise value will be wrapped as a Promise object, so return new Error(‘ Error!! Resolve (new Error(‘ Error!!! ‘)).
Of course, if you throw an error, you can use either of the following 👇 :
return Promise.reject(new Error('error!!! '));// orthrow new Error('error!!! ')
Copy the code
7. Then catch returns a value that cannot wet the promise itself
const promise = Promise.resolve().then(() = > {
return promise
})
promise.catch(console.err)
Copy the code
The value returned by. Then or. Catch cannot be the promise itself, otherwise an infinite loop will occur.
So the result will be an error:
Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
Copy the code
8. Value through
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
Copy the code
The parameters of.then or.catch are expected to be functions, and pass-through occurs when passing non-functions.
The value of resolve(1) is passed directly to the last THEN, because the first and second THEN are not functions; one is a number and the other is an object.
// ans1
Copy the code
9. Two arguments to then
Two arguments to the.then function:
The first argument is the function that handles the Promise success, and the second is the function that handles the failure.
This means that the value of promise.resolve (‘1’) goes into the successful function and the value of promise.reject (‘2’) goes into the failed function.
Promise.reject('err!!! ')
.then((res) = > {
console.log('success', res)
}, (err) = > {
console.log('error', err)
}).catch(err= > {
console.log('catch', err)
})
Copy the code
// ans
'error' 'error!!! '
Copy the code
It enters the second argument in then(), and if it is removed, it enters the catch() :
Promise.reject('error!!! ')
.then((res) = > {
console.log('success', res)
}).catch(err= > {
console.log('catch', err)
})
Copy the code
// ans
'catch' 'error!!! '
Copy the code
Here’s another example:
Promise.resolve() .then(function success (res) { throw new Error('error!!! ')}, function fail1 (err) { console.log('fail1', err)}).catch(function fail2 (err) { console.log('fail2', err)})
Copy the code
Since the Promise calls resolve(),.then() should execute success(), but success() throws an error that is caught by a catch(), not by fail1.
// ans
fail2 Error: error!!!
at success
Copy the code
10. finally
Finally, there are three key points:
-
The.finally() method executes regardless of the final state of the Promise object
-
The.finally() callback does not accept any arguments, so there is no way in the.finally() function to know whether the Promise is resolved or rejected
-
It will eventually return a previous Promise value by default, but if an exception is thrown it will return the exception’s Promise.
Promise.resolve('1')
.then(res= > {
console.log(res) / / '1'
})
.finally(() = > {
console.log('finally')})Promise.resolve('2')
.finally(() = > {
console.log('finally2')
return 'I'm the value returned by finally2'
})
.then(res= > {
console.log('Then function after Finally2', res)
})
Copy the code
The.finally of both promises is executed, and even if finally2 returns a new value, its subsequent then() function receives ‘2’, so it prints:
// ans
'1'
'finally2'
'finally'
'Then function after Finally2' '2'
Copy the code
For why finally2 prints before Finally, see the parsing in the next example.
But before we do that, let’s make sure that finally throws an exception:
Promise.resolve('1')
.finally(() = > {
console.log('finally1')
throw new Error('I'm an exception thrown in finally')
})
.then(res= > {
console.log('Then function after finally', res)
})
.catch(err= > {
console.log('Catch error', err)
})
Copy the code
// ans
'finally1'
'Catch error' Error: I am afinallyThe exception thrown byCopy the code
But if you return new Error(‘ I am an exception thrown in finally ‘), then function 1 after finally will be printed.
Then look at a more difficult example:
function promise1 () {
let p = new Promise((resolve) = > {
console.log('promise1') // 1:'promise'
resolve('1')})return p
}
function promise2 () {
return new Promise((resolve, reject) = > {
reject('error')
})
}
promise1()
.then(res= > console.log(res)) / / 2: '1'
.catch(err= > console.log(err))
.finally(() = > console.log('finally1')) // 4: 'finally1'
promise2()
.then(res= > console.log(res))
.catch(err= > console.log(err)) // 3: Error: error
.finally(() = > console.log('finally2')) // 5: 'finally2'
Copy the code
Execution process:
- First, two functions are defined
promise1
andpromise2
Anyway, keep reading.
The 'promise1' function is called first, and then the 'new Promise' synchronization code is executed to print 'promise1'Copy the code
-
When resolve(1) is encountered, change the state of P to Resolved and save the result.
-
Now that the function content in promise1 is finished, the function is exited
-
As promise1().then() is resolved, add the promise1().then() micro-task to the list of micro-tasks (this is the first micro-task).
-
It is important to note that the code does not follow the chain call, adding.finally() first to the list of microtasks. That is because.then is a microtask, and everything that follows the chain must wait for the current microtask to complete, so we will leave.finally() alone.
-
Further down the line, the promise2() function returns a new Promise that has no synchronization code to execute, so reject(‘error’) changes the Promise status to Rejected
-
Jump out of the promise2 function and encounter promise2().catch(), add it to the current microtask queue (which is the second microtask), and the chain call will wait until the task is finished, just like.then().
-
Promise1 ().then(), execute it, print 1, then encountered. Finally () adds the microtask to the microtask list (the third microtask) and waits to execute
-
Then execute promise2(). Catch () to print an error and add finally2 to the microtask list (the fourth microtask)
-
OK, this round is complete again, but there are two new microtasks left on the list of microtasks, so finally1 and finally2 are executed.
// ans
'promise1'
'1'
'error'
'finally1'
'finally2'
Copy the code
Anything that follows a chain call will not be executed until the previous call completes.
Just as finally() waits for promise1().then() to execute before adding finally() to the microtask queue, the same is true if you replace finally() with then().
4. All and race in the Promise
.all() receives a set of asynchronous tasks, executes them in parallel, and does not execute the callback until all asynchronous operations are complete.
.race() also receives a set of asynchronous tasks and executes them in parallel, retaining only the results of the first completed asynchronous operation. The other methods still execute, but the results are discarded.
1. Promise.all()
If you define a Promise directly in a script file, the first argument to its constructor is executed immediately, like this:
const p1 = new Promise(r= > console.log('Print now'))
Copy the code
So to control when it executes, we can wrap a function around it and call it when we need it to execute:
function runP1 () {
const p1 = new Promise(r= > console.log('Print now'))
return p1
}
runP1() // Only executed when this function is called
Copy the code
Now build a function like this:
function runAsync (x) {
const p = new Promise(r= > setTimeout(() = > r(x, console.log(x)), 1000))
return p
}
Copy the code
The function passes in a value x, and then prints out the x at an interval of one second.
What if I execute it with.all()?
function runAsync (x) {
const p = new Promise(r= > setTimeout(() = > r(x, console.log(x)), 1000))
return p
}
Promise.all([runAsync(1), runAsync(2), runAsync(3)])
.then(res= > console.log(res))
Copy the code
// ans// After an interval of one second, the console prints 1, 2, 3, and an array [1, 2, 3]. 123 [1, 2, 3]
Copy the code
With ALL, you can perform multiple asynchronous operations in parallel and process all returned data in a single callback.
The. Then () callback after.all() receives the results of all asynchronous operations.
And the array order in this result is the same as the array order received by promise.all ()!!
There is a scene is very suitable for this, some game materials more applications, when opening the web page, pre-load the need to use a variety of resources such as pictures, Flash and various static files. After everything is loaded, we’ll initialize the page.
2. Catch Catches the first exception in all
Add a runReject function that rejects an error after 1000 * x seconds.
Meanwhile, the.catch() function catches the first exception in.all() and executes it only once.
function runAsync (x) {
const p = new Promise(r= > setTimeout(() = > r(x, console.log(x)),1000))
return p
}
function runReject (x) {
const p = new Promise((res, rej) = > setTimeout(() = > rej(`Error: ${x}`.console.log(x)),1000*x))
return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])
.then(res= > console.log(res)) // Because of a set of exceptions, all will not enter here
.catch(err= > console.log(err))
Copy the code
// ans
// Output after 1s
1
3
// output after 2s
2
Error: 2
// Output after 4s
4
Copy the code
.catch is the exception that catches first, which in this case is the result of runReject(2).
In addition, if there is an exception in a set of asynchronous operations, it is not entered in the first callback argument of.then().
Notice, why don’t you say don’t enter.then()
Because!!!!! The second argument to the.then() method can also catch errors
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])
.then(res= > console.log(res),
err= > console.log(err))
Copy the code
3. Promise.race()
The.race() method, which only gets the results of the first completed execution. Other asynchronous tasks continue, but race does not care about the results of those tasks.
Modify the 6.1 topic
function runAsync (x) {
const p = new Promise(r= > setTimeout(() = > r(x, console.log(x)), 1000))
return p
}
Promise.race([runAsync(1), runAsync(2), runAsync(3)])
.then(res= > console.log('result: ', res))
.catch(err= > console.log(err))
Copy the code
// ans
1
'result:' 1
2
3
Copy the code
What is the use of this race? There are many scenarios, such as using Race to set a timeout for an asynchronous request and perform the corresponding operation after the timeout
4.
Modify the 6.2 topic
function runAsync(x) {
const p = new Promise(r= >
setTimeout(() = > r(x, console.log(x)), 1000));return p;
}
function runReject(x) {
const p = new Promise((res, rej) = >
setTimeout(() = > rej(`Error: ${x}`.console.log(x)), 1000 * x)
);
return p;
}
Promise.race([runReject(0), runAsync(1), runAsync(2), runAsync(3)])
.then(res= > console.log("result: ", res))
.catch(err= > console.log(err));
Copy the code
The same goes for the error. In this case, runReject(0) runs out first, so catch() is used:
// ans
0
'Error: 0'
1
2
3
Copy the code
A small summary.then()
and.race()
-
Promise.all() takes a set of asynchronous tasks, executes them in parallel, and does not execute the callback until all the asynchronous operations are complete.
-
.race() also receives a set of asynchronous tasks and executes them in parallel, retaining only the results of the first completed asynchronous operation. The other methods still execute, but the results are discarded.
-
The array order in the promise.all () result is the same as the array order received by promise.all ().
-
If the array passed by all and race contains an asynchronous task that throws an exception, only the first error thrown will be caught, either by the second argument to then or by a subsequent catch. This does not affect the execution of other asynchronous tasks in the array.
5. async/await
1. async/await/promise
async function async1() {
console.log("async1 start")
await sync2()
console.log("async1 end")}async function async2() {
console.log("async2")
}
async1();
console.log('start')
Copy the code
// ans
'async1 start'
'async2'
'start'
'async1 end'
Copy the code
Process analysis:
- First of all, we created two functions, so let’s not look at where the function was created, but where it was called
- found
async1
The function is called, and then you look at the content of the call - Executes the synchronization code in the function
async1 start
And then I ran into himawait
It will blockasync1
The execution of the following code is therefore executed firstasync2
Synchronization code inasync2
“And jump outasync1
- Jump out of the
async1
Function to execute the synchronization codestart
- After a round of macro tasks have all been executed, execute the previous one
await
The restasync1 end
.
It can be understood as:
The statements immediately following await are placed in the new Promise, and the next line and statements after await are placed in promise.then
Pseudocode to convert await to promise.then:
async function async1() {
console.log("async1 start");
// The original code
// await async2();
// console.log("async1 end");
// The converted code
new Promise(resolve= > {
console.log("async2")
resolve()
}).then(res= > console.log("async1 end"))}async function async2() {
console.log("async2");
}
async1();
console.log("start")
Copy the code
The difference between await and Promise, what if we replace await async2() with a new Promise?
async function async1() {
console.log("async1 start");
new Promise(resolve= > {
console.log('promise')})console.log("async1 end");
}
async1();
console.log("start")
Copy the code
// ans
'async1 start'
'promise'
'async1 end'
'start'
Copy the code
New Promise() does not block the execution of the synchronous code async1 end that follows.
2. async setTimeout
Add a timer to async2 in 5.1
async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); }async function async2() { setTimeout(() = > { console.log('timer')},0) console.log("async2"); }async1();console.log("start")
Copy the code
The timer is always executed last and is placed in the delay queue for the next macro task.
// ans
'async1 start'
'async2'
'start'
'async1 end'
'timer'
Copy the code
3. Add more timers
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
setTimeout(() = > { // The third timer
console.log('timer1')},0)}async function async2() {
setTimeout(() = > { // The first timer
console.log('timer2')},0)
console.log("async2");
}
async1();
setTimeout(() = > { // Second timer
console.log('timer3')},0)
console.log("start")
Copy the code
// ans
'async1 start'
'async2'
'start'
'async1 end'
'timer2'
'timer3'
'timer1'
Copy the code
4 Return is not a promise
Normally, the await command in async is a Promise object that returns the result of that object.
But if it is not a Promise object, it returns the corresponding value, equivalent to promise.resolve ().
async function fn () {
// return await 1234
/ / is equivalent to
return 123
}
fn().then(res= > console.log(res))
Copy the code
// ans
123
Copy the code
5 await received no response
async function async1 () {
console.log('async1 start');
await new Promise(resolve= > {
console.log('promise1')})console.log('async1 success'); // Will not be executed
return 'async1 end' // Will not be executed
}
console.log('srcipt start')
async1().then(res= > console.log(res))
console.log('srcipt end')
Copy the code
In async1, a Promise after await has no return value. That is, its state is always pending, so it is awaiting, await but no response.
So nothing after await is executed, including.then after async1.
// ans
'script start'
'async1 start'
'promise1'
'script end'
Copy the code
6. await+promise+resolve
async function async1 () {
console.log('async1 start');
await new Promise(resolve= > {
console.log('promise1')
resolve('promise1 resolve')
}).then(res= > console.log(res))
console.log('async1 success');
return 'async1 end'
}
console.log('srcipt start')
async1().then(res= > console.log(res))
console.log('srcipt end')
Copy the code
If there is a return value, it will execute normally
// ans
'script start'
'async1 start'
'promise1'
'script end'
'promise1 resolve'
'async1 success'
'async1 end'
Copy the code
7.
async function async1 () {
console.log('async1 start');
await new Promise(resolve= > {
console.log('promise1')
resolve('promise resolve')})console.log('async1 success');
return 'async1 end'
}
console.log('srcipt start')
async1().then(res= > { // This has nothing to do with the resolve value of new Promise
console.log(res) // res should be async1 return 'async1 end'
})
new Promise(resolve= > {
console.log('promise2')
setTimeout(() = > {
console.log('timer')})})Copy the code
// ans
'script start'
'async1 start'
'promise1'
'promise2'
'async1 success' // Async1 new Promise has no relation to async1().then()
'async1 end'
'timer'
Copy the code
8. Interview Question 1
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");// The first microtask
}
async function async2() {
console.log("async2");
}
console.log("script start");
setTimeout(function() { // The first timer, macro task
console.log("setTimeout");
}, 0);
async1();
new Promise(function(resolve) {
console.log("promise1");
resolve();
}).then(function() {
console.log("promise2"); // Second microtask
});
console.log('script end')
Copy the code
// ans
'script start'
'async1 start'
'async2'
'promise1'
'script end'
'async1 end'
'promise2'
'setTimeout'
Copy the code
9.
async function testSometing() {
console.log("Executive testSomething");
return "testSometing";
}
async function testAsync() {
console.log("Executive testAsync");
return Promise.resolve("hello async");
}
async function test() {
console.log("test start...");
const v1 = await testSometing();
console.log(v1); // await the statement equivalent to.then(), the first microtask, so skip ahead
const v2 = await testAsync();
console.log(v2); // The third microtask will be skipped
console.log(v1, v2); // Perform the last microtask in sequence
}
test();
var promise = new Promise(resolve= > {
console.log("promise start...");
resolve("promise");
});
promise.then(val= > console.log(val)); // Second microtask
console.log("test end...");
Copy the code
// ans
'test start... '
'execution testSomething'
'promise start... '
'test end... '
'testSomething' // The second round takes the first microtask
'execution testAsync'
'promise' // The second microtask in the second round
'hello async' // Perform the third microtask in the third round
'testSomething' 'hello async' // Round 3 performs the last microtask in sequence
Copy the code
6. Async processing errors
1. await followed by an exception or error
async function async1 () {
await async2();
console.log('async1');
return 'async1 success'
}
async function async2 () {
return new Promise((resolve, reject) = > {
console.log('async2')
reject('error')
})
}
async1().then(res= > console.log(res))
Copy the code
If an error is thrown in an async function, the error result is terminated and execution does not proceed.
// ans
'async2'
Uncaught (in promise) error
Copy the code
Same thing if you throw new Error.
2. To ensure that the error does not affect async functions, use a try catch
async function async1 () {
try {
await Promise.reject('error!!! ')}catch (e) {
console.log(e)
}
console.log('async1')
return Promise.resolve('async1 success')
}
async1().then(res= > console.log(res))
console.log('script start')
Copy the code
// ans
'script start'
'error!!! '
'async1'
'async1 success'
Copy the code
Or you can simply follow promise.reject with a catch() method:
async function async1 () {
// try {
// await Promise.reject('error!!! ')
// } catch(e) {
// console.log(e)
// }
await Promise.reject('error!!! ')
.catch(e= > console.log(e)) // Add a catch here
console.log('async1');
return Promise.resolve('async1 success')
}
async1().then(res= > console.log(res))
console.log('script start')
Copy the code
7. The comprehensive problem
1.
const first = () = > (new Promise((resolve, reject) = > {
console.log(3);
let p = new Promise((resolve, reject) = > {
console.log(7);
setTimeout(() = > { // The first macro task
console.log(5);
resolve(6); // Only the first resolve is recorded
console.log(p)
}, 0)
resolve(1); // the result of p
});
resolve(2); // First result
p.then((arg) = > { // The first microtask
console.log(arg); / / 1
});
}));
first().then((arg) = > { // Second microtask
console.log(arg); / / 2
});
console.log(4);
Copy the code
// ans
3
7
4
1
2
5
Promise{<resolved>: 1}
Copy the code
Process analysis:
- The first piece of code defines a function, so we have to look at where it’s executed, and find out where it is, right
4
Before, so check it outfirst
The contents of the function. (This step is kind of like the problem1.5
) - function
first
It returns onenew Promise()
, so execute the synchronization code inside first3
- And then I met another one
new Promise()
, directly execute the synchronization code inside7
- after
7
Later, inp
, encounters a timer, first puts it in the next macro task queue, and then goes down - met
resolve(1)
Right herep
To change the state toresolved
And the return value is1
, but don’t do it here either - Jump out of the
p
, metresolve(2)
Here,resolve(2)
, means thefirst
The one returned by the functionPromise
If your status changes, ignore it. - And then I ran into
p.then
, add it to the list of microtasks for the loop, and wait for execution - Jump out of the
first
Delta function, I’ve met itfirst().then()
, add it to the list of microtasks for this cycle (p.then
The following execution) - The synchronization code is then executed
4
- The synchronization codes of this round are all executed, and the list of microtasks is searched and found
p.then
andfirst().then()
, execute in turn, print out1 and 2
- When this round of task is completed, it is found that there is still a timer that has not run out, and then the content of this timer is executed, and the synchronization code is executed
5
- And then I met another one
resolve(6)
, it is placed inp
In, butp
The state of theta has changed before, so it’s not going to change here, in other wordsresolve(6)
It’s kind of useless, so it’s printed outp
forPromise{<resolved>: 1}
. (This step is similar to the problem3.1
)
2.
const async1 = async() = > {console.log('async1');
setTimeout(() = > { // The first macro task
console.log('timer1')},2000)
await new Promise(resolve= > {
console.log('promise1')})console.log('async1 end') // await is equivalent to.then(), first microtask, but !!!! Await returns no value, then nothing else is executed
return 'async1 success' // This return is not in await, so await has no return value
}
console.log('script start');
async1().then(res= > console.log(res)); // Second microtask
console.log('script end');
Promise.resolve(1)
.then(2) // then expectation is a function, 2 is not a function, penetration
.then(Promise.resolve(3))
.catch(4)
.then(res= > console.log(res)) / / 1
setTimeout(() = > {
console.log('timer2') // Second macro task
}, 1000)
Copy the code
// ans
'script start'
'async1'
'promise1'
'script end'
1
// 'async1 end' // Since await has no return value, nothing after await is executed
// 'async1 success' // because async has no return value
'timer1'
'timer2'
Copy the code
async
In the functionawait
thenew Promise
If there is no return value, nothing is done5.5
).then
Parameters in a function are expected to be functions, and pass-through occurs if they are not3.8
)
3.
const p1 = new Promise((resolve) = > {
setTimeout(() = > { // The first macro task
resolve('resolve3');
console.log('timer1')},0)
resolve('resovle1'); // The resolve state is resolve1
resolve('resolve2'); // No new state changes are received
}).then(res= > {
console.log(res) // The first microtask
setTimeout(() = > { // Second macro task
console.log(p1) // The return value of.finally, which was the last Promise, is undefined for.then()
}, 1000)
}).finally(res= > { // Second microtask
console.log('finally', res)
})
Copy the code
// ans
'resolve1'
'finally' undefined
'timer1'
Promise{<resolve>: undefined}
Copy the code
Note:
-
Once the state of a Promise changes, it cannot be changed (similar to item 3.5)
-
Finally () is a decoy (similar to 3.10) because the res in finally() is a decoy (similar to 3.10) because the finally() callback will not accept the Promise and will execute regardless of whether the Promise state is resolved or Rejected.
-
The last timer prints p1, which is the return value of.finally, We know that the return value of.finally, if no errors are thrown, defaults to the return value of the last Promise (also mentioned in 3.10). In this case, the last Promise was.then(), but this.then() does not return a value. So p1’s printed Promise will be undefined, and if you add a return 1 to the bottom of the timer, it will change to 1
8. Big Factory interview questions
1. Use promise to print 1,2, and 3 every second
I Promise to reduce it
const arr = [1.2.3]
arr.reduce((p, x) = > {
return p.then(() = > {
return new Promise(r= > {
setTimeout(() = > r(console.log(x)), 1000)})})},Promise.resolve())
Copy the code
2. Use Promise to realize alternating and repeated light of traffic lights
Red light 3 seconds on once, yellow light 2 seconds on once, green light 1 second on once; How do I make three lights turn on again and again? (Implemented with Promise) Three lighting functions already exist:
// ans
function red() {
console.log('red');
}
function green() {
console.log('green');
}
function yellow() {
console.log('yellow');
}
const light = function (timer, cb) {
return new Promise(resolve= > {
setTimeout(() = >{
cb()
resolve()
}, timer)
})
}
const step = function () {
Promise.resolve().then(() = > {
return light(3000, red)
}).then(() = > {
return light(2000, green)
}).then(() = > {
return light(1000, yellow)
}).then(() = > {
return step()
})
}
step();
Copy the code
3. Encapsulate a method for loading images asynchronously
In the image onload function, use resolve
function loadImg(url) {
return new Promise((resolve, reject) = > {
const img = new Image();
img.onload() = function() {
console.log("Image loading completed")
resolve(img)
}
img.onerror = function() {
reject(new Error('Could not load image at ' + url))
}
img.src = url
})
}
Copy the code