根据JSON数据创建模拟的JavaScript响应

时间:2019-06-12 22:45:51

标签: javascript json fetch

我有一个应用程序可以进行许多异步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 => { /* … */ })`*

2 个答案:

答案 0 :(得分:2)

我假设data.close.json().thendata.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;
  }