首页 > 解决方案 > 您可以将 UrlFetchApp 转换为 Apps Script 中的 Promise 吗?

问题描述

UrlFetchApp.fetch 同步执行,导致执行速度变慢。是否可以将 UrlFetchApp 转换为 promise?

我一直在考虑这种方法:

  1. 作为 Promise返回HTTPResponse.getContent()并将所有 url 添加到队列中。
  2. 推迟它们的执行直到getContent().then()被调用。
  3. getContent()调用任何一个 url 时,用于fetchAll获取所有结果并清除队列。

你觉得这种方法有什么问题吗?

标签: google-apps-scriptpromiseurlfetch

解决方案


从理论上讲,该方法似乎是合理的,尤其是因为已知.fetchAll异步执行

  • .fetch()call 是实际提取发生的地方。fetch因此,应在调用之前插入 UrlFetchApp 对象的任何挂钩。

  • 您可以使用 aProxy object来挂钩.fetch调用UrlFetchApp以返回HTTPResponse带有对象的虚拟thenable对象

  • 然后按照问题中的说明使用fetchAllon .getContent call。

  • 但是请注意,apps 脚本中的 promise 可能会也可能不会按照问题注释 #1 到 #4中的说明异步执行。但是,这不应该是您的方法的问题。

鉴于 Promise 的挑剔性质和不明确的文档,最好在任何生产环境中避免使用它们。实现批处理请求的更好方法是使用带有thenable对象的普通自定义函数:

function test() {
  /**
   * @description Batches requests until then is called on a response
   *   and fetches all batched requests
   * @return {object} A then object, which when called fetches the batch
   * @param {string} url Url to fetch
   * @param {object} options Options to fetch. See UrlFetchApp.fetch
   */
  const fetchAsBatch = function fetch(requests, url, options) {
    options.url = url;
    requests.add(options);
    return {
      then: func => {
        const responses = func(UrlFetchApp.fetchAll([...requests]));
        requests.clear();// clear current batch
        return responses;
      },
    };
  }.bind(this, new Set());

  const successHandlerLogger = responses => {
    /*Do something with all responses*/
    console.log(responses.map(response => response.getContentText()));
  };
  fetchAsBatch('https://example.com', { method: 'get' });
  fetchAsBatch('https://httpbin.org/post', { method: 'post' }).then(
    successHandlerLogger
  );
  fetchAsBatch('https://google.com', {}).then(successHandlerLogger);
}

function test() {
  /**
   * @description Batches requests until then is called on a response
   *   and fetches all batched requests
   * @return {object} A then object, which when called fetches the batch
   * @param {string} url Url to fetch
   * @param {object} options Options to fetch. See UrlFetchApp.fetch
   */
  const fetchAsBatch = function fetch(requests, url, options) {
    options.url = url;
    requests.add(options);
    return {
      then: func => {
        const responses = func(UrlFetchApp.fetchAll([...requests]));
        requests.clear();
        return responses;
      },
    };
  }.bind(this, new Set());

  const successHandlerLogger = responses => {
    /*Do something with all responses*/
    console.log(responses.map(response => response.getContentText()));
  };
  fetchAsBatch('https://example.com', { method: 'get' });
  fetchAsBatch('https://httpbin.org/post', { method: 'post' }).then(
    successHandlerLogger
  );
  fetchAsBatch('https://google.com', {}).then(successHandlerLogger);
}
/*Mock urlfetchapp library to return requests without fetch*/
const UrlFetchApp = {
  fetchAll: requests =>
    requests.map(request => ({
      getContentText: () => request,
    })),
};

test();


推荐阅读