0
\$\begingroup\$

Is there more efficient, proper way, to write a function like this? The effect I want to achieve is to remove CSS classes in three steps, one after another.

function loadColors(){
 setTimeout(()=>{
  document.querySelector('.class-1').classList.remove('class-x')
 }, 0);

 setTimeout(()=>{
  document.querySelector('.class-2').classList.remove('class-z')
 }, 100);

 setTimeout(()=>{
  document.querySelector('.class-3').classList.remove('class-y')
 }, 200);
}
\$\endgroup\$
4
  • \$\begingroup\$ Write a small library? \$\endgroup\$ Commented Aug 26, 2018 at 14:01
  • 2
    \$\begingroup\$ Welcome to Code Review! This question looks a bit sketchy and simplified. I suggest that you post a real demo with the three effects that you are trying to achieve — press Ctrl-M in the question editor. The best solution might involve nearly no JavaScript at all. \$\endgroup\$ Commented Aug 26, 2018 at 19:54
  • \$\begingroup\$ Depending on your use case it might make sense to use the css transition property to control when your elements change visual state: developer.mozilla.org/en-US/docs/Web/CSS/transition developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/… \$\endgroup\$ Commented Aug 27, 2018 at 15:34
  • \$\begingroup\$ not sure why this is downvoted. \$\endgroup\$ Commented Sep 16, 2023 at 4:32

2 Answers 2

2
\$\begingroup\$

You can save the info in an array,then use Array.forEach() to execute.

const timeoutPieces = [
    [".class-1", "class-x", 0],
    [".class-2", "class-z", 100],
    [".class-3", "class-y", 200],
];
timeoutPieces.forEach(p => {
    setTimeout(() => {
        document.querySelector(p[0]).classList.remove(p[1])
    }, p[2]);
});

If you want to use es6,and have clear name for vairables,use Array Destructing

timeoutPieces.forEach(([selector, aClass, time]) => {
    setTimeout(() => {
        document.querySelector(selector).classList.remove(aClass)
    }, time);
});

It's using array,is because the selector,class and timer you used are not likely to have relation,if you are certain the time for timeout is incremental by 100,you can use Array.map()

const addTimer = (piece, index) => [...piece, index * 100];
const timeoutPieces = [
    [".class-1", "class-x"],
    [".class-2", "class-z"],
    [".class-3", "class-y"],
].map(addTimer);

timeoutPieces.forEach(([query, aClass, time]) => {
    setTimeout(() => {
        document.querySelector(query).classList.remove(aClass)
    }, time);
});
\$\endgroup\$
1
\$\begingroup\$

async await and promise

One way to do this is to use promises and an async function.

async functions stop execution each time they encounter an await token and "await" the promise (if any) to resolve before continuing. async functions are also promises themselves so you can await an async function as well.

Example

The example uses a timer event to resolve a promise. The function threeStep uses the wait function to pause execution for the set time.

To show how you can also chain the async function It repeats the 3 steps after the first lot are done by using the async function's returned promise to start the second three steps.

const wait = time => new Promise(tick => setTimeout(tick, time));
async function threeStep(time) {
    log(`Step A and wait ${time}ms`);
    await wait(time);
    log(`Step B and wait ${time}ms`);
    await wait(time);
    log(`Step C all done`);      
}

threeStep(2000)
   .then(() => {
      log("Do it again");
      threeStep(1000);  
   });

// a very hacky log function, don't try this at home. :P
function log(data) { logText.innerHTML += data + "<br>" }
<div id="logText"></div>

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.