Most of the time you have to use JS to manipulate the DOM. Is this “synchronous” or “asynchronous”?

1. Operate the CHESTNUT of DOM

Normally, in js execution, operations on the DOM are performed synchronously,

<body></body>

<script>
    var body = document.querySelector('body');
    console.log(`1`);
    var cDiv = document.createElement('div');
    console.log(cDiv)
    console.log(`2`);
    body.appendChild(cDiv)
    console.log(body);
</script>

Copy the code

The above results are consistent with our expected results, top-down sequential synchronous execution, here highlights, JS engine threads.

So let’s do a little bit of modification

<style>
	.easy {
		width: 200px;
		height: 200px;
		background: lightgoldenrodyellow;
	}
	.hard {
		background: lightsalmon;
		transition: 2s all;
	}
</style>

<body></body>

<script>
	var body = document.querySelector('body');
	console.log(`1`);
	var cDiv = document.createElement('div');
	console.log(cDiv);
	console.log(`2`);
	body.appendChild(cDiv)
	console.log(body);
	cDiv.classList.add('easy') console.log(`3`); / / = = = = = = = = = = = = = = = = = = = = = =for(var i = 0; i<3000000000; i++); cDiv.classList.add('hard')
	console.log(cDiv)
 // ======================
</script>

Copy the code

Since is synchronous execution, that before I add the second style hard block, theoretically in the case of blocking the < div > should be the background color is light yellow? But running completely wrong ah, out of the slow not to say, actually straight orange. Here we highlight the GUI rendering thread

Two, to clarify the question

  1. There is a block, the block does not show the existing style, is it synchronous execution?
  2. console.log()Is the content not empty, just returns slowly, looks like asynchronous execution?
  3. Overstyling is ignored, but background color overwriting is implemented, why?

Three, answer the questions in turn

  1. The order of js execution is not detailed here. Common promises, setTimeout,

  2. Since synchronous execution has the effect of “asynchronous”, here is the main point: JS engine thread and GUI rendering thread. That is, the JS engine thread and the GUI rendering thread are mutually exclusive, and this is due to the “synchronization” between threads resulting in an “asynchronous” effect when manipulating the DOM.

  3. Why didn’t the

    style work? Obviously there is a transition effect. The reason: browser rendering implements optimization strategies that combine styles from the same DOM.

Four,

  1. Js engine threadwithGUI rendering threadThe mutual exclusion between threads causes the pairjsThe “asynchrony” problem with DOM manipulation.
  2. GUI rendering threadOptimizations that can be executed render the resulting style.

The details of the render thread are beyond the scope of this discussion.

Although the cause has been found, the problem seems to remain.

5. Solve problems

If the product must be created from JS div has cool effects (such as the overstyling above). Ha ha ha ha

Direct collation of a self-knowledge of the solution of the problem ideas, here is not just excessive style, similar problems are still effective.

Analysis problem:

  1. The transition effect is at least from A to B, that is, there are at least two different states;
  2. As mentioned aboveGUI rendering threadwithJs engineThe mutex creates a “synchronous” execution effect, so create<div>It’s already lagging behind, missing A.
  3. And because of theGUI rendering threadOptimization strategy, the final result B will cover everything that can be covered. Missing A (to be overridden) and later rendered to appear indocumentInside.
  4. It is already B, and there is no A state, and the excessive effect is invalid.

The solution is to make<div>You have an initial state A and you’re done. (Render the generated DOM to the document ahead of time)


Solution 1:

	cDiv.classList.add('easy') / /for(var i = 0; i<3000000000; i++);setTimeout(() => {
		cDiv.classList.add('hard')}, 0)Copy the code

Use setTimeout to change the execution queue. This means that the js engine is manually delayed, the JS engine is terminated, the suspended GUI rendering thread is executed, and the transition effect is OK after it has the initial state A.

Solution two (recommended) :

	cDiv.classList.add('easy') cDiv.clientLeft; // Any method that triggers page backflow can be cdiv.classlist.add ('hard')
Copy the code

If you can make the JS engine lag, you can also make the GUI render thread advance, using any method that triggers immediate backflow, to make state A previously in the render queue take effect. The relative advantage is that method two is more readable or operable than the same method that triggers backflow, which is a natural pursuit for good teams.