search
HomeWeb Front-endJS TutorialCache Fetched AJAX Requests Locally: Wrapping the Fetch API

Cache Fetched AJAX Requests Locally: Wrapping the Fetch API

This article was written by invited author Peter Bengtsson. SitePoint's special guest post is designed to bring you great content from well-known writers and speakers in the JavaScript community

This article demonstrates how to implement a local cache of fetched requests so that if executed repeatedly, it will be read from the session store. The benefit of this is that you don't need to write custom code for every resource you want to cache.

If you want to show off your next JavaScript party and show off your various skills in handling Promise, state-of-the-art APIs, and local storage, read on.

Main gains

  • Using the Fetch API, developers can create local caches of AJAX requests, improving efficiency by reducing redundant network calls and speeding up data retrieval.
  • The simple way to cache using global variables is limited by session persistence; switching to session storage allows data to be reloaded across pages in the same session persistence.
  • Implementation cachedFetch encapsulates the standard fetch calls, which can automatically cache responses based on content type and URL, thus making the cache mechanism universal.
  • Enhancements to
  • cachedFetch include handling cache hits from session storage before making a network request, and managing content expired to avoid using outdated data.
  • Future improvements may include processing binary data and using hash URLs as cache keys to optimize storage and retrieval processes in web applications.

Fetch API

At this point, you should be familiar with fetch. It is a new native API in the browser for replacing the old XMLHttpRequest API.

Can I Use fetch? https://www.php.cn/link/b751ea087892ebeca363034301f45c69 data on the website about the main browser's support for fetch function.

Where not all browsers are perfectly implemented, you can use GitHub's fetch polyfill (there are Fetch standard specifications here if you're doing nothing all day).

Simple Alternatives

Suppose you know exactly which resource you need to download and you only want to download it once. You can use global variables as cache as follows:

let origin = null;
fetch('https://httpbin.org/get')
  .then(r => r.json())
  .then(information => {
    origin = information.origin; // 您的客户端IP
  });

// 需要延迟以确保fetch已完成
setTimeout(() => {
  console.log('您的来源是 ' + origin);
}, 3000);

CodePen example

This only depends on global variables to hold cached data. The direct problem is that if you reload the page or navigate to a new page, the cached data will disappear.

Before we dissect its shortcomings, let's upgrade the first simple solution.

fetch('https://httpbin.org/get')
  .then(r => r.json())
  .then(info => {
    sessionStorage.setItem('information', JSON.stringify(info));
  });

// 需要延迟以确保fetch已完成
setTimeout(() => {
  let info = JSON.parse(sessionStorage.getItem('information'));
  console.log('您的来源是 ' + info.origin);
}, 3000);

CodePen example

The first direct problem is that fetch is based on Promise, which means we can't determine when it will be done, so for the sake of certainty we should not rely on its execution until its Promise parses.

The second problem is that this solution is very specific to specific URLs and specific cached data snippets (key information in this example). What we want is a universal URL-based solution.

First implementation – Keep it simple

Let's create a wrapper around fetch which also returns a promise. The code that calls it may not care whether the result is from the network or from the local cache.

So imagine you used to do this:

let origin = null;
fetch('https://httpbin.org/get')
  .then(r => r.json())
  .then(information => {
    origin = information.origin; // 您的客户端IP
  });

// 需要延迟以确保fetch已完成
setTimeout(() => {
  console.log('您的来源是 ' + origin);
}, 3000);

CodePen example

Now you want to wrap it so that duplicate network calls can benefit from local cache. Let's simply call it cachedFetch, so the code looks like this:

fetch('https://httpbin.org/get')
  .then(r => r.json())
  .then(info => {
    sessionStorage.setItem('information', JSON.stringify(info));
  });

// 需要延迟以确保fetch已完成
setTimeout(() => {
  let info = JSON.parse(sessionStorage.getItem('information'));
  console.log('您的来源是 ' + info.origin);
}, 3000);
The first time it runs, it needs to parse the request over the network and store the result in the cache. The second time should be extracted directly from local storage.

Let's start with the code that simply wraps the fetch function:

fetch('https://httpbin.org/get')
  .then(r => r.json())
  .then(issues => {
    console.log('您的来源是 ' + info.origin);
  });

CodePen example

This works, but of course it doesn't work. Let's first implement the storage of extracted data.

cachedFetch('https://httpbin.org/get')
  .then(r => r.json())
  .then(info => {
    console.log('您的来源是 ' + info.origin);
  });

CodePen example

There are a lot to do here.

The first promise returned by fetch will actually continue to perform the GET request. If there is a problem with CORS (cross-origin resource sharing), the .text(), .json(), or .blob() methods will not work.

The most interesting feature is that we have to

Clone the Response object returned by the first Promise. If we don't, we overinject ourselves, and when the end users of Promise try to call .json() (for example), they get this error:

Another thing to note is the careful handling of the response type: we only store the response when the status code is 200 and the content type is application/json or text/*. This is because sessionStorage can only store text.

const cachedFetch = (url, options) => {
  return fetch(url, options);
};
The following is an example of how to use it:

The clever thing about this solution so far is that it works without interfering with JSON

and

HTML requests. When it is an image, it does not try to store it in sessionStorage.

const cachedFetch = (url, options) => {
  // 使用URL作为sessionStorage的缓存键
  let cacheKey = url;
  return fetch(url, options).then(response => {
    // 让我们只在内容类型为JSON或非二进制内容时存储在缓存中
    let ct = response.headers.get('Content-Type');
    if (ct && (ct.match(/application\/json/i) || ct.match(/text\//i))) {
      // 有一个.json()而不是.text(),但我们将它存储在sessionStorage中作为字符串。
      // 如果我们不克隆响应,它将在返回时被使用。这样我们就可以不干扰。
      response.clone().text().then(content => {
        sessionStorage.setItem(cacheKey, content);
      });
    }
    return response;
  });
};
Second implementation - Actual return cache hit

Therefore, our first implementation is only responsible for storing the response of the request. However, if you call cachedFetch the second time, it still won't try to retrieve anything from sessionStorage. What we need to do is to return a Promise, and the Promise needs to parse a Response object.

Let's start with a very basic implementation:

CodePen example

It works!
<code>TypeError: Body has already been consumed.</code>

To see how it actually works, open the CodePen of this code and then open the "Network" tab of the browser in the developer tools. Press the Run button a few times (the upper right corner of CodePen) and you should see that only the images are requesting repeatedly over the network.

One of the cleverness of this solution is the lack of "callback pasta". Since the sessionStorage.getItem call is synchronous (i.e. blocking), we don't have to deal with "Is it in local storage?" in the Promise or callback. And we will return cached results only if there is content. If not, the if statement will only continue to execute the regular code.

The third implementation – What about the expiration time?

So far we have been using sessionStorage, it's like localStorage, just that sessionStorage is cleared when you start a new tab. This means we are leveraging a "natural way" to avoid cache time too long. If we use localStorage instead and cache something, it will always get stuck there even if the remote content has changed, which is bad.

A better solution is to let usercontrol. (In this case, the user is the web developer who uses our cachedFetch function). Just like Memcached or Redis storage on the server side, you can set a lifetime that specifies how long it should be cached.

For example, in Python (using Flask):

let origin = null;
fetch('https://httpbin.org/get')
  .then(r => r.json())
  .then(information => {
    origin = information.origin; // 您的客户端IP
  });

// 需要延迟以确保fetch已完成
setTimeout(() => {
  console.log('您的来源是 ' + origin);
}, 3000);

Now, neither sessionStorage nor localStorage has this feature built in, so we have to implement it manually. We will do this by always logging the timestamp of the stored time and using it to compare possible cache hits.

But what will it look like before we do this? For example:

fetch('https://httpbin.org/get')
  .then(r => r.json())
  .then(info => {
    sessionStorage.setItem('information', JSON.stringify(info));
  });

// 需要延迟以确保fetch已完成
setTimeout(() => {
  let info = JSON.parse(sessionStorage.getItem('information'));
  console.log('您的来源是 ' + info.origin);
}, 3000);

The key new thing we will add is that every time we save the response data, we will also record when when store it. But please note that now we can also switch to more reliable storage of localStorage instead of sessionStorage. Our custom expired code will ensure we don't get very stale cache hits in the persistent localStorage. So this is our ultimate working solution:

fetch('https://httpbin.org/get')
  .then(r => r.json())
  .then(issues => {
    console.log('您的来源是 ' + info.origin);
  });
CodePen example

The realization of the future – better, more fancy, cooler

Not only do we avoid over-accessing these web APIs, the best part is that localStorage is much faster than dependent networks. Please refer to this blog post for a comparison of localStorage vs. XHR:

localForage vs. XHR

. It measures other things, but basically concludes that localStorage is very fast and disk cache warm-up is rare. So how do we further improve our solutions?

Processing binary response

Our implementation here does not cache non-text content (such as images), but there is no reason not to cache. We need more code. In particular, we may want to store more information about the Blob. Each response is basically a blob. For text and JSON, it's just an array of strings. Type and size do not matter, as you can infer from the string itself. For binary content, the blob must be converted to an ArrayBuffer.

For curious people, to view the implementation extensions that support images, please check this CodePen: [https://www.php.cn/link/946af3555203afdb63e571b873e419f6].

Use hash cache key

Another potential improvement is to trade space for speed by hashing each URL (we use as keys) to make it smaller. In the example above, we're only using some very small and concise URLs (e.g. httpbin.org/get), but if you have very long URLs, there are a lot of query string content, and there are a lot of these URLs, then they will add up to a lot.

The solution to this problem is to use this clever algorithm, which is considered safe and fast:

let origin = null;
fetch('https://httpbin.org/get')
  .then(r => r.json())
  .then(information => {
    origin = information.origin; // 您的客户端IP
  });

// 需要延迟以确保fetch已完成
setTimeout(() => {
  console.log('您的来源是 ' + origin);
}, 3000);

If you like this, check out this CodePen: [https://www.php.cn/link/946af3555203afdb63e571b873e419f6]. If you check the storage in the web console, you will see a key similar to 557027443.

Conclusion

You now have a working solution that you can add to your web application, where you are probably using the web API and you know that responses can be cached well for your users.

The last thing might be a natural extension of this prototype, that is, to move it beyond the article, into a real, specific project with tests and readmes and publish it on npm - but that's left to be said later!

FAQs about cached extracted AJAX requests (FAQ)

What is the importance of caching fetched AJAX requests?

Caching fetched AJAX requests is critical to improving the performance of your web application. It allows the browser to store a copy of the server response so that it does not have to make the same request again. This reduces the load on the server and speeds up the loading time of the web page, thus providing a better user experience.

How does the Fetch API work with cache?

Fetch API provides a powerful and flexible way to make HTTP requests. It includes a built-in caching mechanism that allows you to specify how requests should interact with the cache. You can set the cache mode to "default", "no-store", "reload", "no-cache", "force-cache", or "only-if-cached", each with different levels of cache control.

What are the different cache modes in the Fetch API and what do they mean?

The Fetch API provides several cache modes. "default" follows standard HTTP caching rules. "no-store" bypasses the cache completely. "reload" ignores any cached data and sends new requests. "no-cache" uses the server to verify data before using the cached version. "force-cache" uses cached data regardless of its freshness. "only-if-cached" only uses it when the cache data is available, otherwise it fails.

How to implement cache in AJAX request?

You can implement cache in AJAX requests by setting the cache attribute in AJAX settings. If set to true, it will allow the browser to cache the response. Alternatively, you can use the cache options of the Fetch API to better control the behavior of the cache.

How to prevent cache in AJAX requests?

To prevent caching in AJAX requests, you can set the cache property in AJAX settings to false. This will force the browser not to store its response in its cache. Alternatively, you can use the "no-store" caching option of the Fetch API to bypass cache entirely.

What is the difference between caching in AJAX and Fetch API?

While both AJAX and Fetch APIs provide caching mechanisms, the Fetch API provides greater flexibility and control. AJAX's cache property is a simple boolean value that allows or does not allow cache. On the other hand, the cache option of the Fetch API allows you to specify how requests should interact with the cache, giving you more granular control.

How does caching affect the performance of my web application?

Cache can significantly improve the performance of web applications. By storing a copy of the server response, the browser does not have to make the same request again. This reduces the load on the server and speeds up the loading time of the web page. However, the cache must be managed correctly to ensure that your users see the latest content.

Can I control the cache behavior of a single AJAX request?

Yes, you can control the cache behavior of a single AJAX request by setting the cache attribute in the AJAX settings for each request. This allows you to specify whether the browser should cache the response.

How to clear the cache of AJAX requests?

Clearing the cache requested by AJAX can be done by setting the cache property to false in the AJAX settings. This will force the browser not to store its response in its cache. Alternatively, you can use the "reload" cache option of the Fetch API to ignore any cached data and send new requests.

What are some best practices for caching AJAX requests?

Some best practices for caching AJAX requests include: understanding different cache modes and when to use them, managing cache correctly to ensure users see the latest content, and using the cache options of the Fetch API for better control over caches. When deciding on a caching strategy, the nature of the data and user experience must also be considered.

The above is the detailed content of Cache Fetched AJAX Requests Locally: Wrapping the Fetch API. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Behind the Scenes: What Language Powers JavaScript?Behind the Scenes: What Language Powers JavaScript?Apr 28, 2025 am 12:01 AM

JavaScript runs in browsers and Node.js environments and relies on the JavaScript engine to parse and execute code. 1) Generate abstract syntax tree (AST) in the parsing stage; 2) convert AST into bytecode or machine code in the compilation stage; 3) execute the compiled code in the execution stage.

The Future of Python and JavaScript: Trends and PredictionsThe Future of Python and JavaScript: Trends and PredictionsApr 27, 2025 am 12:21 AM

The future trends of Python and JavaScript include: 1. Python will consolidate its position in the fields of scientific computing and AI, 2. JavaScript will promote the development of web technology, 3. Cross-platform development will become a hot topic, and 4. Performance optimization will be the focus. Both will continue to expand application scenarios in their respective fields and make more breakthroughs in performance.

Python vs. JavaScript: Development Environments and ToolsPython vs. JavaScript: Development Environments and ToolsApr 26, 2025 am 12:09 AM

Both Python and JavaScript's choices in development environments are important. 1) Python's development environment includes PyCharm, JupyterNotebook and Anaconda, which are suitable for data science and rapid prototyping. 2) The development environment of JavaScript includes Node.js, VSCode and Webpack, which are suitable for front-end and back-end development. Choosing the right tools according to project needs can improve development efficiency and project success rate.

Is JavaScript Written in C? Examining the EvidenceIs JavaScript Written in C? Examining the EvidenceApr 25, 2025 am 12:15 AM

Yes, the engine core of JavaScript is written in C. 1) The C language provides efficient performance and underlying control, which is suitable for the development of JavaScript engine. 2) Taking the V8 engine as an example, its core is written in C, combining the efficiency and object-oriented characteristics of C. 3) The working principle of the JavaScript engine includes parsing, compiling and execution, and the C language plays a key role in these processes.

JavaScript's Role: Making the Web Interactive and DynamicJavaScript's Role: Making the Web Interactive and DynamicApr 24, 2025 am 12:12 AM

JavaScript is at the heart of modern websites because it enhances the interactivity and dynamicity of web pages. 1) It allows to change content without refreshing the page, 2) manipulate web pages through DOMAPI, 3) support complex interactive effects such as animation and drag-and-drop, 4) optimize performance and best practices to improve user experience.

C   and JavaScript: The Connection ExplainedC and JavaScript: The Connection ExplainedApr 23, 2025 am 12:07 AM

C and JavaScript achieve interoperability through WebAssembly. 1) C code is compiled into WebAssembly module and introduced into JavaScript environment to enhance computing power. 2) In game development, C handles physics engines and graphics rendering, and JavaScript is responsible for game logic and user interface.

From Websites to Apps: The Diverse Applications of JavaScriptFrom Websites to Apps: The Diverse Applications of JavaScriptApr 22, 2025 am 12:02 AM

JavaScript is widely used in websites, mobile applications, desktop applications and server-side programming. 1) In website development, JavaScript operates DOM together with HTML and CSS to achieve dynamic effects and supports frameworks such as jQuery and React. 2) Through ReactNative and Ionic, JavaScript is used to develop cross-platform mobile applications. 3) The Electron framework enables JavaScript to build desktop applications. 4) Node.js allows JavaScript to run on the server side and supports high concurrent requests.

Python vs. JavaScript: Use Cases and Applications ComparedPython vs. JavaScript: Use Cases and Applications ComparedApr 21, 2025 am 12:01 AM

Python is more suitable for data science and automation, while JavaScript is more suitable for front-end and full-stack development. 1. Python performs well in data science and machine learning, using libraries such as NumPy and Pandas for data processing and modeling. 2. Python is concise and efficient in automation and scripting. 3. JavaScript is indispensable in front-end development and is used to build dynamic web pages and single-page applications. 4. JavaScript plays a role in back-end development through Node.js and supports full-stack development.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

SublimeText3 English version

SublimeText3 English version

Recommended: Win version, supports code prompts!

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

Atom editor mac version download

Atom editor mac version download

The most popular open source editor