Promise basic usage

Js in order to solve the problem of asynchronous execution of the single thread, introduced the event loop queue system, this system is lined up one by one in the queue waiting for macro mission, settimeout is a macro task, promise is a typical task, concept of micro task is relatively macro tasks, can put the micro tasks by macro task queue. Because the macro task is executed sequentially, if the current macro task has micro tasks, the next macro task will be executed only after all the micro tasks of the current macro task are completed. So promise and setTimeout appear right next to each other in the code, and the promise callback must be executed before setTimeout is executed. Here’s an example:

setTimeout(()=>console.log("d"), 0)
var r = new Promise(function(resolve, reject){
     resolve()
});
r.then(() => { 
		var begin = Date.now();
		while(Date.now() - begin < 1000);
		console.log("c1") 
		new Promise(function(resolve, reject){
        resolve()
		}).then(() => console.log("c2"))
});
// c1 c2 d
Copy the code

The output sequence is C1, c2, and d. Settimeout is followed by a promise, which must execute the promise first. In the then callback of the promise, the promise is forced to wait for a second first. The set of actions runs out, and then we go back to setTimeout. This example is a good example of the relationship between promises (microtasks) and setTimeout (macro tasks).

Promise combining requestAnimationFrame

Promise can be used in a variety of scenarios in a project, but the use of Promise in combination with requestAnimationFrame is rare, and I encountered this requirement in my project.

Let’s start with requestAnimationFrame, which is often used to write animations and is more precise and performs better than setInterval and setTimeout. RequestAnimationFrame is also a macro task, as mentioned earlier in the promise introduction about macro tasks and microtasks.

The requirement now is to call another function after an animation has finished, a process that can be simply interpreted as “see what you can see.”

Understand requestAnimationFrame

RequestAnimationFrame = requestAnimationFrame = requestAnimationFrame

<div id='alimate' style="background-color: brown; width: 100px; height: 100px;" ></div> <script> const element = document.getElementById('alimate'); let start; function step(timestamp) { if (start === undefined) start = timestamp; const elapsed = timestamp - start; // Use 'math.min ()' here to make sure the element stops at exactly 200px. Element.style. transform = 'translateX(' + Elapsed, 200) + 'px '; If (elapsed < 2000) {/ / stop in two seconds animation window. RequestAnimationFrame (step); } } window.requestAnimationFrame(step); </script>Copy the code

I put a little bit of code on top of it, so you can see it directly. This official example is worth studying, and that’s why I copied it, with a few points to make:

  • The step parameter timestamp is a valued decimal number of type double that represents the time at which the current callback function step was called
  • Cancel the animation after 2 seconds, the animation stops only after 2 seconds, no step callback is triggered
  • To cancel the callback, cancelAnimationFrame can be cancelAnimationFrame, which takes the return value of requestAnimationFrame

There is time to look at requestAnimationFrame garbage collection later, but the performance impact of this persistent animation is worth investigating if the above code is not conditional.

Combine promises with requestAnimationFrame

RequestAnimationFrame is a macro task, so write a macro task in a promise, which we often do, like this:

var f = new Promise((resolve, reject) => {
		console.log('a')
		setTimeout(resolve,100);
})
f.then(() => { console.log('res') })
Copy the code

The same applies to requestAnimationFrame. With the usage example above, we can write:

<div id='alimate' style="background-color: brown; width: 100px; height: 100px;" ></div> <script> const element = document.getElementById('alimate'); let start; var f = new Promise((resolve, reject) => { function step(timestamp) { if (start === undefined) start = timestamp; const elapsed = timestamp - start; // Use 'math.min ()' here to make sure the element stops at exactly 200px. Element.style. transform = 'translateX(' + Elapsed, 200) + 'px '; If (Elapsed < 2000) {// Stop the animation requestAnimationFrame(step) after 2 seconds; }else { resolve() } } requestAnimationFrame(step); }) f.hen (() => {element.innerhtml = "Animation is over!" ; }) </script>Copy the code

Note that the body of the promise is actually a requestAnimationFrame function. The model can be simply written as follows:

new Promise((resolve, reject) => {
		requestAnimationFrame(f)
}).then()
Copy the code

The key is where to write the callback function f! ? If you write it outside of the promise, you’ll have a problem when the animation ends and the promise callback needs to be triggered. Look at the code:

New Promise((resolve, reject) => {requestAnimationFrame(f)}).then() function f () {Copy the code

As far as I know, resolve can only be called within promises, and the promise. resolve usage is only suitable for encapsulating asynchronous functions. In this case, it is best to write requestAnimationFrame and its callback in promiset as I do. Just wait until the time is right to call resolve.

It is possible to pass resolve as the second argument if you must write it outside:

<div id='alimate' style="background-color: brown; width: 100px; height: 100px;" ></div> <script> const element = document.getElementById('alimate'); let start; function step(timestamp,resolve) { if (start === undefined) start = timestamp; const elapsed = timestamp - start; // Use 'math.min ()' here to make sure the element stops at exactly 200px. Element.style. transform = 'translateX(' + Elapsed, 200) + 'px '; If (Elapsed < 2000) {// Stop the animation requestAnimationFrame(step) after 2 seconds; }else { resolve() } } var f = new Promise((resolve, reject) => { var s; requestAnimationFrame(step(s, resolve)); }) f.hen (() => {element.innerhtml = "Animation is over!" ; })Copy the code

The consequence of this is that the first parameter of step is no longer a timestamp, but you can write one yourself, and you can animate it. Resolve is a time stamp. If you write resolve in the first place, then resolve will not be executed.

References:

  • Relearn the front End (Geek Time — Winter)
  • Developer.mozilla.org/zh-CN/docs/…
  • Stackoverflow.com/questions/6…