我有一个应用程序可以进行许多异步fetch
调用,其中一些是相同的。
我有一个函数,该函数通过基于参数为每个请求创建伪唯一标识符来对fetch
(例如fetchPlus
)进行超集。这样,我可以将结果存储在sessionStorage
中并对其进行访问。
function fetchCacheStore(hash) {
const storeItem = 'fetch_' + hash;
return {
getCache: function () {
return JSON.parse(sessionStorage.getItem(storeItem));
},
setCache: function (data) {
sessionStorage.setItem(storeItem, JSON.stringify(data));
setTimeout(function () { sessionStorage.removeItem(storeItem); }, 25); // Clear the cache item shortly after
},
};
}
function fetchPlus() {
const stringHasher = function (s) { // Adapted from https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript/22429679#comment94234739_7616484
for (var i = h = 0; i < s.length; i++) {
h = Math.imul(31, h) + s.charCodeAt(i) | 0;
}
return btoa(h);
}
let thisCallDetails = JSON.stringify(Array.prototype.slice.call(arguments).sort());
let fetchCallHash = stringHasher(thisCallDetails);
let fetchCache = fetchCacheStore(fetchCallHash);
let fetchCacheGet = fetchCache.getCache();
let promise;
if (fetchCacheGet === null) { // The data is not cached
promise = fetch(...arguments); // Create the fetch call
promise.then(data => {
data.close.json().then(content => {
fetchCache.setCache(content);
});
}); // Store the result in the cache
} else {
let dataHeaders = { "status": 200, "Content-Type": "application/json" };
promise = new Response(fetchCacheGet, dataHeaders); // Programatically create a Response
}
return promise;
}
除了数据sessionStorage
中存在的所有内容之外,其他所有方法都运行良好,我直接返回的是JSON对象,而不是Response
,因此在我的代码中,当我进行类似所以:
fetchPlus(url, params)
.then(response => response.json())
.then(data => …)
我最终遇到一个错误,让我知道我无法在json()
上运行response
。
行promise = new Response(fetchCacheGet, dataHeaders);
可能是错误的,但是我不确定如何将数据“反转”为原始fetch
调用中的数据。也许我缺少明显的东西。也许这都是错误的。
我愿意接受建议,但是已经设置了此应用程序,因此无法从代码库中删除所有.then(response => response.json())
。
此外,我知道我的代码并不是同类中最好的,所以请原谅我。再次,只要有建设性,就接受建议。
如果有人有空闲时间,我希望能帮助您完成这项工作。
感谢下面的@AuxTaxo's answer,我已经解决了我的问题。对于任何有兴趣的人,这里是更新的代码:
function fetchCacheStore(hash) {
const storeItem = 'fetch_' + hash;
return {
getCache: function () {
return sessionStorage.getItem(storeItem);
},
setCache: function (data) {
sessionStorage.setItem(storeItem, data);
setTimeout(function () { sessionStorage.removeItem(storeItem); }, 1000); // Clear the cache item after a short while
},
};
}
function fetchPlus() {
const stringHasher = function (s) { // Adapted from https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript/22429679#comment94234739_7616484
for (var i = h = 0; i < s.length; i++) {
h = Math.imul(31, h) + s.charCodeAt(i) | 0;
}
return btoa(h);
}
let thisCallDetails = JSON.stringify(Array.prototype.slice.call(arguments).sort());
let fetchCallHash = stringHasher(thisCallDetails);
let fetchCache = fetchCacheStore(fetchCallHash);
let fetchCacheGet = fetchCache.getCache();
let promise;
if (fetchCacheGet === null) { // The data is not cached
promise = fetch(...arguments); // Create the fetch call
promise.then(data => {
data.clone().text().then(content => {
fetchCache.setCache(content) // Store the result in the cache
});
});
} else {
let dataHeaders = { "status": 200, headers: { "Content-Type": "application/json" } };
// Programatically create a Response object, which works as a Promise
promise = Promise.race([new Response(fetchCacheGet, dataHeaders)]);
}
return promise;
}
// Used as: `fetchPlus(url, params).then(response => response.json()).then(data => { /* … */ })`*
答案 0 :(得分:2)
我假设data.close.json().then
是data.clone().json().then
的错字。
new Response()
需要一个字符串(在其他选项中),但是您正在向其传递一个对象。最终,响应正文被设置为"[object Object]"
,.json()
令人窒息。
您可以通过在将对象传递给Response构造函数之前对对象进行字符串化来修补问题,但更好的解决方案是尽可能长时间地使用字符串。您的Response主体是字符串,并且Storage对象存储字符串,因此将response.text()
的结果存储在缓存中而不是response.json()
中。
此外,您只将结果缓存 25毫秒,因此sessionStorage
保持跨页面刷新的数据的优势似乎没有用。只需使用一个普通对象作为缓存即可。并且dataHeaders
应该是{ "status": 200, headers: { "Content-Type": "application/json" } }
。
答案 1 :(得分:1)
function fetchPlus() {
...
let promise;
if (fetchCacheGet === null) { // The data is not cached
promise = fetch(...arguments)
.then(data => {
return data.json()
.then(content => {
// read the response and cache
fetchCache.setCache(content);
const init = {
'status': 200,
'statusText': 'SuperSmashingGreat!'
};
return new Response(JSON.stringify(content), init); <-- recreate the response and it.
});
}); // Store the result in the cache
} else {
let dataHeaders = {
'status': 200,
'statusText': 'SuperSmashingGreat!'
};
promise = new Response(JSON.stringify(fetchCacheGet), dataHeaders); // Programatically create a Response
}
return promise;
}