Создать смоделированный ответ JavaScript из данных JSON - PullRequest
1 голос
/ 13 июня 2019

У меня есть приложение, которое выполняет много асинхронных вызовов 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 /4792022/generatsiya-hesha-iz-stroki-v-javascriptcomment94234739_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 ниже, я решил свою проблему.Для тех, кто заинтересован, вот обновленный код:

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 /4792022/generatsiya-hesha-iz-stroki-v-javascriptcomment94234739_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 ]

2 голосов
/ 13 июня 2019

Я полагаю, data.close.json().then это опечатка data.clone().json().then.

new Response() ожидает (среди прочих параметров) строку, но вы передаете ей объект. Тело ответа в конечном итоге устанавливается на "[object Object]", что .json() включается.

Вы можете исправить проблему, структурировав свой объект перед передачей его конструктору Response, но лучшим решением будет работать со строками как можно дольше. Ваши тела ответа - это строки, а объекты хранилища хранят строки, поэтому в кэше хранится результат response.text() вместо response.json().

Кроме того, вы кэшируете результат только на 25 миллисекунд , поэтому преимущество sessionStorage в сохранении данных при обновлении страницы не кажется полезным. Просто используйте простой объект в качестве кеша. И dataHeaders должно быть { "status": 200, headers: { "Content-Type": "application/json" } }.

0 голосов
/ 13 июня 2019
  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;
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...