function drainTileRequestQueue(tileRequests, results, rejectOnTileFail) {
  // nothing left to do
  if (!tileRequests.length) {
    return Promise.resolve();
  }

  // consume an item from the queue, which will
  //  mutate the request and result lists, and return true if we should
  //  immediately attempt to consume the next item as well
  const success = attemptConsumeNextQueueItem(
    tileRequests,
    results,
    rejectOnTileFail,
  );
  if (success) {
    return drainTileRequestQueue(tileRequests, results, rejectOnTileFail);
  }

  // wait a small fixed amount of time first, before retrying the same request again
  return delay(100).then(() => {
    return drainTileRequestQueue(tileRequests, results, rejectOnTileFail);
  });
}
Recursively consumes all the tileRequests until the list has been emptied
 and a Promise of each result has been put into the results list
@param {object[]} tileRequests The list of requests desired to be made
@param {Array<Promise<void>>} results The list to put all the result promises into
@param {boolean} rejectOnTileFail If true, the promise will be rejected.  If false, returned heights will be undefined.
@returns {Promise<void>} A promise which resolves once all requests have been started

@private