简体   繁体   中英

How to fire a function only after the first one has finished in (JavaScript)

I'm not looking for jQuery solutions please. I tried using the Promise method, and it wouldn't work either I'm trying the callback method but no luck. For right now, as a test I just want it to print something to the console. I'll do the actual code after.

I have a JSFIDDLE HERE for your coding pleasure

This is the callback method I am trying now as I think it's the simplest

const logoAnimation = () => {      
  this.logo.classList.add('fade-out-zoom-out');
  this.blueCnt.classList.add('fade-out');
  this.circWrapper.classList.add('dashed-border');
  this.clickAbove.classList.add('text-fade-out');
  this.welcome.classList.add('text-fade-in');   
}

const rotateBorder = () => {
  console.log('I run after animation')
}

const render = () => {
  console.log(logoAnimation())
    
  logoAnimation(() => {
    rotateBorder();
  })          
}

I did try the Promise method... I'll take either one to be frank (An explanation of it would be ever better please)

  function logoAnimation() {     
    return new Promise(function(resolve, reject) {
      this.logo.classList.add('fade-out-zoom-out');
      this.blueCnt.classList.add('fade-out');
      this.circWrapper.classList.add('dashed-border');
      this.clickAbove.classList.add('text-fade-out');
      this.welcome.classList.add('text-fade-in'); 
    })  
  }

  const rotateBorder = () => {
    console.log('I run after animation')
  }

  function render() {
    logoAnimation().then(function () {
      rotateBorder()
    })
  }

Then just an onclick call from somewhere

<img class="logo" id="logo" onclick="render()" src="/path/img"/>

Your problem is essentially the same in both versions.

In the first one the implementation of logoAnimation doesn't care about the callback you pass it - in fact it doesn't accept any arguments at all, so it will happily ignore anything passed to it. If you intend to pass it a callback, then you need to ensure that you call it ("call it back" - this is where the term "callback" comes from:) inside the function:

const logoAnimation = (callback) => {      
  this.logo.classList.add('fade-out-zoom-out');
  this.blueCnt.classList.add('fade-out');
  this.circWrapper.classList.add('dashed-border');
  this.clickAbove.classList.add('text-fade-out');
  this.welcome.classList.add('text-fade-in');
  callback();
}

In the Promise version, you likewise never call resolve , which is the function passed in to the .then handler. So to get that version to work, you would need to change the implementation like this:

  function logoAnimation() {     
    return new Promise(function(resolve, reject) {
      this.logo.classList.add('fade-out-zoom-out');
      this.blueCnt.classList.add('fade-out');
      this.circWrapper.classList.add('dashed-border');
      this.clickAbove.classList.add('text-fade-out');
      this.welcome.classList.add('text-fade-in');
      resolve();
    })  
  }

I will note that, although in general I'm a big fan of using Promises for asynchronous code rather than old-style spaghetti callbacks, there's nothing asynchronous going on in your examples so I see no need for Promises - I'd just stick with the callback-based version, assuming you need callers of logoAnimation to specify what should happen next.

Unfortunately, css transitions are out of control of JavaScript. Your problem is not with the order of functions.

In order to achieve what you want, you should use setTimeout function and calculate those durations yourself.

You can use a "wait" function in order to mimic waiting:

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

let logo = document.getElementById('logo');
let blueCnt = document.getElementById('blueCnt');
let circWrapper = document.getElementById('circWrapper');
let clickAbove = document.getElementById('clickAbove');
let welcome = document.getElementById('welcome');

function logoAnimation() {     
  this.logo.classList.add('fade-out-zoom-out');
  this.blueCnt.classList.add('fade-out');
  this.circWrapper.classList.add('dashed-border');
  this.clickAbove.classList.add('text-fade-out');
  this.welcome.classList.add('text-fade-in'); 
}

const rotateBorder = () => {
  console.log('I run after animation')
}

function render() {
  logoAnimation()
  wait(1000).then(rotateBorder)
}

Also pay attention that if you do not call the resolve function inside a Promise callback, it won't fulfill and your function call won't reach the chained .then

If you want to run 2 synchronous functions in sequence, you can just run them one at a time:

func1(); 
func2(); // Only runs after func1 has completed.

A quick and dirty solution would be to use a timeout:

  const logoAnimation = () => {      
    this.logo.classList.add('fade-out-zoom-out');
    this.blueCnt.classList.add('fade-out');
    this.circWrapper.classList.add('dashed-border');
    this.clickAbove.classList.add('text-fade-out');
    this.welcome.classList.add('text-fade-in');
    setTimeout(()=>{
        rotateBorder();
    }, 3000);
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM