Javascript Promises

I’m working on some scripts that involve using Location which works using Javascript promises. The issue is that my Javascript is knowledge is super basic at best, and this is something I’ve never seen before. I’ve done some googling, and written a Scriptable script that returns my location.

const promise = new Promise((resolve, reject) => {
  const location = Location.current();  
  if (location) {
    resolve(location);
   }
   else {
      reject(Error("Unable to fetch location"));
     }
 });

  
 promise.then((data) => {
  console.log('Location Determined');
  var latitude = data["latitude"];
  var longitude = data["longitude"];
  var testSentence = "Latitude is " + latitude + " and longitude is " + latitude
  console.log(testSentence);
}, (error) => {
  console.log('Promise rejected.');
});

The problem is now I can’t figure out how to do anything with my variables latitude and longitude. I eventually want to send it to the Dark Sky API and run another promise to get data back from there. As many sites as I’ve looked at, the explanations are just plain confusing. Is there anyone who can think of a decent way to explain what the next step should be?

Thanks for the help fellow Automators!

1 Like

Hi,

I’ll try to explain it without becoming too technical about it.

Location.current() returns a promise. If you’re not used to promises, they can be a bit overwhelming but here’s a super short explanation.

What you get from calling Location.current() is an object that will either carry a value or an error, at some point in the future . Think of it as you are promised a value some time in the future but that value is not ready just yet. However, it might be that you’re not getting a value but an error instead. This happens if the operation fails.

So how do we get the value that arrives some time in the future? Well, we wait. There’s two ways to do that. You can call the .then() function on the promise or use the relatively new keyword await. In your code you are using .then() but you’re not doing it quite right. Using .then() looks like the following:

// We get our promise from Location.current() and then we start waiting for either a value or an error.
Location.current().then(loc => {
  // The promise have returned. We're now holding our location in the "loc" parameter.
}).catch(err => {
  // We couldn't get the value. Instead we caught an error with .catch().
  // For the Location.current() promise this might happen if the user
  // haven't granted access to the location.
})

With the above syntax we can get fancy and start chaining promises by returning one promise when another one is fulfilled. That’s what you would do to load data from the Dark Sky API.

Location.current().then(loc => {
  // Use the location to fetch data from the Dark Sky API.
  // This is not the actual request but just and example.
  let lat = loc["latitude"]
  let lon = loc["longitude"]
  let req = new Request("https://darksky.net/..../?lat=" + lat + "&lon=" + lon)
  return req.loadJSON()
}).then(json => {
  // Now we've got some JSON from the Dark Sky API.
  // Let's see what the JSON contains using Scriptables QuickLook API.
  QuickLook.present(json)
}).catch(err => {
  // We couldn't get the value. Instead we caught an error with .catch().
  // For the Location.current() promise this might happen if the user
  // haven't granted access to the location.
  logError(err)
})

I mentioned there’s two approaches for waiting for a value. The second approach is using the await keyword. When using the await keyword the script will halt and wait for a value or an error. This looks like the following.

let loc = await Location.current()    
// Now we can use the location. If Location.current() fails, exection
// of the script will terminate and an error is shown in the log.
let lat = loc["latitude"]
let lon = loc["longitude"]
let req = new Request("https://darksky.net/..../?lat=" + lat + "&lon=" + lon)
let json = await req.loadJSON()
QuickLook.present(json)

I generally recommend using await over .then() as described in this forum post but it’s a matter of personal preference and the desired result.

Don’t hesitate to ask if you have any questions.

8 Likes

Await is so much easier to wrap my head around. Thanks for taking all that time explaining everything. Once I get the script written I’ll share what I’m using it for in my classroom.

1 Like

This would be a great addition to Scriptables Documentation.