0

I’m developing an organisational chart. I’m looking for tips on restructuring how I handle two es6-promises for a minor performance gain.

On the click event, I do 3 things sequentially:

  1. Play first animation (promise)
  2. Fetch all data (promise)
  3. Play last animation

Ideally, I would like:

  1. Begin fetching data
  2. Play first animation
  3. Play last animation (requires the fetched data, but can’t play before the first animation has ended)

Here is the code in question:

/* Click happened! */

orgWrap.shiftRow({ row: clickY, from: clickX, to: focusX }).then(() => {
    /* Shiftrow is a promise triggering an animation,
       it resolved on 'transitionend' */

    fetch(`api/org/${target.id}/1`).then(result =>  {
        /* a function placing result in the DOM runs
           After data finished loading */

        orgWrap.populateRow({ data: result.children, row: clickY+1 });
        /* The animation which plays last, when shiftRow and fetch has settled */
  });

});

As it stands now, there is an occasional unnecessary delay between shiftRow and populateRow because it fetches all data after the first animation is done and then runs the final animation, instead it should begin to fetch data on the initial click. Any tips on how I can refactor and better utilise promises and the power of async? I prefer to keep the functions which are promises to stay promises, the rest I am willing to change. Any input is greatly appreciated.

Audun Olsen
  • 597
  • 6
  • 17

3 Answers3

2

You can use Promise.all() for the first two promises, then for the third one. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Georgy
  • 2,410
  • 3
  • 21
  • 35
1

Wrap the fetch and begin animation in a Promise.all() and run the end animation after the Promise.all resolves.

So:

async function animate() {
  // some animation logic
}

Promise
  .all([
    animate(), // Beginning animation
    fetch("some.html")
  ])
  .then([, neededFetchData] => {
    return animate(neededFetchData);
  });
zero298
  • 25,467
  • 10
  • 75
  • 100
  • Thank you! I'll accept this answer because you answered with a code example, but omitted all the irrelevant parts of my code. Thus it may be easier to understand for other people swinging by this thread. +1 bonus points for `[, neededFetchData]`, understanding that the first promise only resolves, but doesn't return any value. – Audun Olsen Jan 31 '19 at 13:52
1

You'll want to use Promise.all for this:

/* Click happened! */

Promise.all([
  orgWrap.shiftRow({ row: clickY, from: clickX, to: focusX }), // Shiftrow is a promise triggering an animation, it resolved on 'transitionend'
  fetch(`api/org/${target.id}/1`),
]).then(([animationResult, fetchResult]) => {
  /* a function placing result in the DOM runs after data finished loading */

  return orgWrap.populateRow({ data: result.children, row: clickY+1 }); // The animation which plays last, when shiftRow and fetch has settled
});

Also make sure to chain your promise callbacks instead of unnecessarily nesting them.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375