问题描述
UrlFetchApp.fetch同步执行,使执行速度变慢。是否可以将UrlFetchApp转换为Promise?
我一直在想这种方法:
- 返回
HTTPResponse.getContent()
作为承诺,并将所有网址添加到队列中。 - 将其执行推迟到调用
getContent().then()
之前。 - 调用任意一个网址中的
getContent()
时,请使用fetchAll
获取所有网址 结果并清除队列。
您认为这种方法有什么问题吗?
解决方法
从理论上讲,这种方法似乎是合理的,尤其是因为已知.fetchAll
executes asynchronously。
-
.fetch()
调用是实际获取的地方。因此,在进行fetch
调用之前,应插入UrlFetchApp对象的所有钩子。 -
您可以使用
Proxy object
来挂接.fetch
上的UrlFetchApp
调用,以返回带有HTTPResponse
对象的伪thenable
-
然后按照问题所述在
fetchAll
通话中使用.getContent
。 -
但是请注意,应用程序脚本中的promise可能会或可能不会按照issue comments #1 to #4中的说明异步执行。但是,这不应该与您的方法有关。
鉴于承诺的挑剔性质和不明确的文档,最好在任何生产环境中避免使用它们。实现批处理请求的一种更好的方法是对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,options) {
options.url = url;
requests.add(options);
return {
then: func => {
const responses = func(UrlFetchApp.fetchAll([...requests]));
requests.clear();
return responses;
},{}).then(successHandlerLogger);
}
/*Mock urlfetchapp library to return requests without fetch*/
const UrlFetchApp = {
fetchAll: requests =>
requests.map(request => ({
getContentText: () => request,})),};
test();