How do I put Utilities.sleep() between function ca

2019-08-11 21:27发布

问题:

I have a function that is calculating the distance between two coordinates as follows:

function distance(origin, destination) {
  //Utilities.sleep(Math.random() * 60000);
  destination = destination + "";
  if (destination.split(",").length == 2) {
    var directions = Maps.newDirectionFinder()
    .setOrigin(origin)
    .setDestination(destination)
    .getDirections();
    if (directions.routes.length > 0) {
      return directions.routes[0].legs[0].distance.value / 1000;
    }
    return "-";
  }
  return 0;
}

It is used in the spreadsheet as follows:

=distance("83.342353,23.23353", V2)

The function runs fine but hits the rate limit for url calls since my spreadsheet has more than 200 rows. The error message is:

Service invoked too many times in a short time: urlfetch protected host rateMax. Try Utilities.sleep(1000) between calls. (line 5)

The fix suggested is to put a Utitlies.sleep() in the code. Where exactly should I put this?

回答1:

The problem here is that even if you put Utilities.sleep in there, the function is still being called several times concurrently. That's what Google sheets does normally. It runs functions in parallel to speed things up. So you need to force it to run in sequence which you can achieve with a lock. e.g.

function distance(origin, destination) {
  destination = destination + "";
  if (destination.split(",").length == 2) {
    var lock = LockService.getScriptLock();
    lock.waitLock(20000);
    Utilities.sleep(500);
    var directions = Maps.newDirectionFinder()
    .setOrigin(origin)
    .setDestination(destination)
    .getDirections();
    lock.releaseLock();
    if (directions.routes.length > 0) {
      return directions.routes[0].legs[0].distance.value / 1000;
    }
    return "-";
  }
  return 0;
}

However the quota on the direction finder service is relatively low. Maybe just 1000 uses per day. So you may still run into problems.