Best Practices for Synchronous Javascript Queries?

I'm hoping to get a consensus for how to best handle synchronous queries (those that depend on one to completely finish before executing another). I've had the requirement several times across different apps and I have approached it differently each time.

I have read through the "scripting retool - promises and async queries" documentation, but there's a little voice in my head saying it's outdated and confusing to read.

For example, we want to execute the following steps in order:

let targets = getTargetsFromAPI() // retool query resource
if(targets.length == 0)
  return []
endif

let data = getDataFromAPI() // retool query resource

let resultRows = []

foreach targets as target
  if(data.property == target.property) {
    let resultRow =  // create result row object
    resultRows.push(resultRow)
  }
endforeach

return resultRows;

How would you go about creating a javascript query for this?

Official Documentation

Officially, Retool suggests we use Promises. This code is untested.

  let targets = Promise.resolve(getTargetsFromAPI.trigger());
  let targetsArray = formatDataAsArray(targets);
  if(targets.data.length == 0) {
    return [];
  }

  let data = Promise.resolve(getDataFromAPI.trigger());
  let mrsDataData = mrsData.data[0];
  let resultRows = [];

  _.each(targetsArray, function(target) {
    // do processing and push to resultRows
    let obj = {'foo': target.bar, 'buzz': target.bazz};
    resultRows.push(obj)
  });

  return resultRows;

** Using then()**
I've used this in some of my apps (past me isn't ever as smart as present me), essentially just chaining together a bunch of .then() functions. It's not easy to return values though. Admittedly, I don't have a proper example of how this might work with the above situation and I lack the brain power at the moment to convert it.

return something.trigger()
  .then(resolve => somethingElse.trigger(resolve))
  .then(function(resolve) {
     let variable = resolve.data;
  });

Using Async/Await

It seems to me this is the modern solution. I'm not a JS expert though. I also note that await can only be used inside an async function, so I'm going to wrap all my code in this.

return (async () => {
  let targets = await getTargetsFromAPI.trigger();
  let targetsArray = formatDataAsArray(targets);
  if(targets.data.length == 0) {
    return [];
  }

  let data = await getDataFromAPI.trigger();
  let mrsDataData = mrsData.data[0];
  let resultRows = [];

  _.each(targetsArray, function(target) {
    // do processing and push to resultRows
    let obj = {'foo': target.bar, 'buzz': target.bazz};
    resultRows.push(obj)
  });

  return resultRows;
})();

I suppose await is mostly syntactical sugar for Promise.resolve(), so long as you are in an async function.

Anyways, I'd love to know what some of you have settled on using for best practice when running synchronous scripts. :wink: :smile:

Thanks in advance!

2 Likes

You are on the right track.

This is the pattern I have used extensively for a while now and along with many of the other power users on the forum, consider it a best practice.