您可以将 UrlFetchApp 转换为 Apps 脚本中的承诺吗?
Can you convert UrlFetchApp into a promise in Apps Script?
UrlFetchApp.fetch 同步执行,执行速度慢。是否可以将 UrlFetchApp 转换为 promise?
我一直在想这个方法:
- Return
HTTPResponse.getContent()
作为 Promise 并将所有 url 添加到队列中。
- 推迟执行直到
getContent().then()
被调用。
- 当调用任意一个url的
getContent()
时,使用fetchAll
获取所有
结果并清除队列。
您认为这种方法有什么问题吗?
从理论上讲,该方法似乎很合理,尤其是因为众所周知 .fetchAll
executes asynchronously。
.fetch()
调用是实际获取发生的地方。因此,应在 fetch
调用之前插入 UrlFetchApp 对象的任何挂钩。
您可以使用 Proxy object
挂钩 .fetch
对 UrlFetchApp
的调用 return 带有 thenable
对象
然后按照问题中所述在 .getContent
调用中使用 fetchAll
。
但是请注意,应用程序脚本中的承诺可能会也可能不会异步执行,如 issue comments #1 to #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();
UrlFetchApp.fetch 同步执行,执行速度慢。是否可以将 UrlFetchApp 转换为 promise?
我一直在想这个方法:
- Return
HTTPResponse.getContent()
作为 Promise 并将所有 url 添加到队列中。 - 推迟执行直到
getContent().then()
被调用。 - 当调用任意一个url的
getContent()
时,使用fetchAll
获取所有 结果并清除队列。
您认为这种方法有什么问题吗?
从理论上讲,该方法似乎很合理,尤其是因为众所周知 .fetchAll
executes asynchronously。
.fetch()
调用是实际获取发生的地方。因此,应在fetch
调用之前插入 UrlFetchApp 对象的任何挂钩。您可以使用
Proxy object
挂钩.fetch
对UrlFetchApp
的调用 return 带有thenable
对象然后按照问题中所述在
.getContent
调用中使用fetchAll
。但是请注意,应用程序脚本中的承诺可能会也可能不会异步执行,如 issue comments #1 to #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();