Function Requirements: Simulate traffic light signals and switch green (pass), yellow (wait) and red (stop) in 5 seconds, 1.5 seconds and 3.5 seconds respectively. That is, the default is green, 5 seconds later it is yellow, 1.5 seconds later it is red, 3.5 seconds later it is green again, and so on.
# 1: create a nested state for each state
html
<ul id="traffic" class="wait">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
Copy the code
css
#traffic {
display: flex;
flex-direction: column;
}
#traffic li{
list-style: none;
width: 50px;
height: 50px;
background-color: gray;
margin: 5px;
border-radius: 50%;
}
#traffic.s1 li:nth-child(1) {
background-color: #a00;
}
#traffic.s2 li:nth-child(2) {
background-color: #aa0;
}
#traffic.s3 li:nth-child(3) {
background-color: #0a0;
}
#traffic.s4 li:nth-child(4) {
background-color: #a0a;
}
#traffic.s5 li:nth-child(5) {
background-color: #0aa;
}
Copy the code
js
const traffic = document.getElementById('traffic'); (function reset(){// By default, the traffic className property is set to 's1' traffic.className = 's1'; setTimeout(function(){ traffic.className = 's2'; setTimeout(function(){ traffic.className = 's3'; setTimeout(function(){ traffic.className = 's4'; setTimeout(function(){ traffic.className = 's5'; setTimeout(reset, 1000) }, 1000) }, 1000) }, 1000) }, 1000); }) ();Copy the code
We start by taking the class=traffic element and declaring a reset function. This function sets the traffic element’s className property to ‘s1’ by default. When this is done, it matches the CSS setting below, making the background of the Li element green. Then there are several nested setTimeOut methods.
Disadvantages:
1. If we change the HTML code, the element will not be called traffic and the function will not work. 2. If we want to reuse this function elsewhere, we have to recreate the traffic object there. # Method 2: Abstract data to do state switch
html
<ul id="traffic" class="wait">
<li></li>
<li></li>
<li></li>
</ul>
Copy the code
css
#traffic { display: flex; flex-direction: column; } #traffic li { display: inline-block; width: 50px; height: 50px; background-color: gray; margin: 5px; border-radius: 50%; } #traffic.stop li:nth-child(1) { background-color: #a00; } #traffic.wait li:nth-child(2) { background-color: #aa0; Pass li:nth-child(3) {background-color: #0a0;} // Set the first li element under the class=traffic =pass element to green #traffic. }Copy the code
JS
Const traffic = document.getelementById ('traffic'); const traffic = document.getelementById ('traffic'); Const stateList = [{state: 'wait', last: 1000}, {state: 'stop', last: 3000}, {state: 'pass', last: 3000},]; Function start(traffic, stateList){function applyState(stateIdx) {const {state, last} = stateList[stateIdx]; traffic.className = state; setTimeout(() => { applyState((stateIdx + 1) % stateList.length); }, last) } applyState(0); } start(traffic, stateList);Copy the code
Data abstraction is the definition and aggregation of data into objects that can be processed by a particular process. Simply put, it is the structuring of data. Data abstracted code can be adapted to business needs at different states and times, and we only need to modify the data abstraction without changing the start method.
Disadvantages:
After data abstraction refactoring, our start method is not yet fully encapsulated. Because the start function has a part of the code that changes the external state. We call the part of the code that changes the external state side effects. In general, we can consider stripping out some of the code that has side effects in the function body, which often improves the versatility, stability, and testability of the function.
Method 3: The process abstracts out a polling method
html
<ul id="traffic" class="wait">
<li></li>
<li></li>
<li></li>
</ul>
Copy the code
css
#traffic {
display: flex;
flex-direction: column;
}
#traffic li{
display: inline-block;
width: 50px;
height: 50px;
background-color: gray;
margin: 5px;
border-radius: 50%;
}
#traffic.stop li:nth-child(1) {
background-color: #a00;
}
#traffic.wait li:nth-child(2) {
background-color: #aa0;
}
#traffic.pass li:nth-child(3) {
background-color: #0a0;
}
Copy the code
js
const traffic = document.getElementById('traffic'); function wait(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function poll(... fnList){ let stateIndex = 0; return async function(... args){ let fn = fnList[stateIndex++ % fnList.length]; return await fn.apply(this, args); } } async function setState(state, ms){ traffic.className = state; await wait(ms); // let trafficStatePoll = poll(setstate.bind (null, 'wait', 1000), setstate.bind (null, 'stop', 3000), setState.bind(null, 'pass', 3000)); (async function() { // noprotect while(1) { await trafficStatePoll(); }} ());Copy the code
# Method 4: Wrap the Primise object
html
<ul id="traffic" class="wait">
<li></li>
<li></li>
<li></li>
</ul>
Copy the code
css
#traffic {
display: flex;
flex-direction: column;
}
#traffic li{
display: inline-block;
width: 50px;
height: 50px;
background-color: gray;
margin: 5px;
border-radius: 50%;
}
#traffic.stop li:nth-child(1) {
background-color: #a00;
}
#traffic.wait li:nth-child(2) {
background-color: #aa0;
}
#traffic.pass li:nth-child(3) {
background-color: #0a0;
}
Copy the code
js
const traffic = document.getElementById('traffic'); Function wait(time){return new Promise(resolve => setTimeout(resolve, time)); Function setState(state){traffic. ClassName = state; } async function start(){ //noprotect while(1){ setState('wait'); await wait(1000); setState('stop'); await wait(3000); setState('pass'); await wait(3000); } } start();Copy the code
The setTimeOut method is wrapped as a wait function, which wraps the setTimeOut method with a promise and returns the Promise object.
With this wait function, the somewhat obscure nesting of setTimeOut can easily be rewritten into an await loop in an async function.