惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
C
CERT Recently Published Vulnerability Notes
C
Cisco Blogs
Cloudbric
Cloudbric
The Last Watchdog
The Last Watchdog
L
LINUX DO - 热门话题
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Application and Cybersecurity Blog
Application and Cybersecurity Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Security Archives - TechRepublic
Security Archives - TechRepublic
TaoSecurity Blog
TaoSecurity Blog
V2EX - 技术
V2EX - 技术
H
Heimdal Security Blog
S
Security Affairs
L
Lohrmann on Cybersecurity
Hacker News - Newest:
Hacker News - Newest: "LLM"
Simon Willison's Weblog
Simon Willison's Weblog
WordPress大学
WordPress大学
小众软件
小众软件
Security Latest
Security Latest
AWS News Blog
AWS News Blog
Apple Machine Learning Research
Apple Machine Learning Research
GbyAI
GbyAI
Engineering at Meta
Engineering at Meta
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
F
Full Disclosure
S
Schneier on Security
L
LangChain Blog
MyScale Blog
MyScale Blog
Know Your Adversary
Know Your Adversary
P
Privacy International News Feed
Google Online Security Blog
Google Online Security Blog
Scott Helme
Scott Helme
Stack Overflow Blog
Stack Overflow Blog
爱范儿
爱范儿
A
Arctic Wolf
Martin Fowler
Martin Fowler
B
Blog RSS Feed
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
The Register - Security
The Register - Security
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园_首页
Latest news
Latest news
F
Fortinet All Blogs
G
GRAHAM CLULEY
T
The Exploit Database - CXSecurity.com
Hacker News: Ask HN
Hacker News: Ask HN

Dmitri Pavlutin Blog

Pure Functions in JavaScript: A Beginner's Guide Record Type in TypeScript: A Quick Intro How to Write Comments in React: The Good, the Bad and the Ugly 4 Ways to Create an Enum in JavaScript React forwardRef(): How to Pass Refs to Child Components TypeScript Function Types: A Beginner's Guide How to Use v-model to Access Input Values in Vue Mastering Vue refs: From Zero to Hero Environment Variables in JavaScript: process.env 5 Must-Know Differences Between ref() and reactive() in Vue How to Destructure Props in Vue (Composition API) Triangulation in Test-Driven Development How to Use nextTick() in Vue Programming to Interface Vs to Implementation A Smarter JavaScript Mapper: array.flatMap() Array Grouping in JavaScript: Object.groupBy() How to Access ES Module Metadata using import.meta JSON Modules in JavaScript How to Trim Strings in JavaScript TypeScript Function Overloading How to Debounce and Throttle Callbacks in Vue How to Show/Hide Elements in Vue Sparse vs Dense Arrays in JavaScript How to Fill an Array with Initial Values in JavaScript Covariance and Contravariance in TypeScript What are Higher-Order Functions in JavaScript? How to Use TypeScript with React Components Index Signatures in TypeScript How to Use React useReducer() Hook unknown vs any in TypeScript A Guide to React Context and useContext() Hook How to Use Promise.any() 2 Ways to Remove a Property from an Object in JavaScript 'return await promise' vs 'return promise' in JavaScript How to Use Promise.allSettled() How to Use fetch() with JSON JavaScript Promises: then(f,f) vs then(f).catch(f) What is a Promise in JavaScript? How to Use Promise.all() A Simple Guide to Component Props in React Don't Stop Me Now: How to Use React useTransition() hook A Simple Explanation of JavaScript Variables: const, let, var ES Modules Dynamic Import How to Memoize with React.useMemo() How to Cleanup Async Effects in React Why Math.max() Without Arguments Returns -Infinity How to Debounce and Throttle Callbacks in React Don't Confuse Function Expressions and Function Declarations in JavaScript How to Use ES Modules in Node.js Solving a Mystery Behavior of parseInt() in JavaScript How to Use Array Reduce Method in JavaScript 3 Ways to Merge Arrays in JavaScript A Guide to Jotai: the Minimalist React State Management Library The Difference Between Values and References in JavaScript How to Implement a Queue in JavaScript A Helpful Algorithm to Determine "this" value in JavaScript React useRef() Hook Explained in 3 Steps 7 Interview Questions on "this" keyword in JavaScript. Can You Answer Them? How to Greatly Enhance fetch() with the Decorator Pattern 7 Interview Questions on JavaScript Closures. Can You Answer Them? What's a Method in JavaScript? array.sort() Does Not Simply Sort Numbers in JavaScript How to Solve the Infinite Loop of React.useEffect() The New Array Method You'll Enjoy: array.at(index) What's the Difference between DOM Node and Element? Why Promises Are Faster Than setTimeout()? Everything About Callback Functions in JavaScript How React Updates State 5 Mistakes to Avoid When Using React Hooks 5 Best Practices to Write Quality JavaScript Variables Type checking in JavaScript: typeof and instanceof operators 3 Ways to Check if a Variable is Defined in JavaScript React Forms Tutorial: Access Input Values, Validate, Submit Forms Prototypal Inheritance in JavaScript How to Timeout a fetch() Request How to Learn JavaScript If You're a Beginner A Simple Explanation of React.useEffect() A Simple Explanation of JavaScript Iterators How to Use React Controlled Inputs Everything about null in JavaScript Getting Started with Arrow Functions in JavaScript An Interesting Explanation of async/await in JavaScript Front-end Architecture: Stable and Volatile Dependencies Is it Safe to Compare JavaScript Strings? How to Access Object's Keys, Values, and Entries in JavaScript What Actually is a String in JavaScript? 3 Ways to Shallow Clone Objects in JavaScript (w/ bonuses) Checking if an Array Contains a Value in JavaScript JavaScript Event Delegation: A Beginner's Guide How to Parse URL in JavaScript: hostname, pathname, query, hash 3 Ways to Detect an Array in JavaScript How to Get the Screen, Window, and Web Page Sizes in JavaScript 3 Ways to Check If an Object Has a Property/Key in JavaScript How to Compare Objects in JavaScript Object.is() vs Strict Equality Operator in JavaScript Own and Inherited Properties in JavaScript 5 Differences Between Arrow and Regular Functions How to Use Object Destructuring in JavaScript Your Guide to React.useCallback() 5 JavaScript Scope Gotchas
How to Use Fetch with async/await
Dmitri Pavlutin · 2020-09-15 · via Dmitri Pavlutin Blog

The Fetch API is the default tool for performing network operations in web applications. Although fetch() is generally easy to use, there are some nuances to be aware of.

In this post, you'll find the common scenarios of how to use fetch() with async/await syntax. You'll understand how to fetch data, handle fetch errors, cancel a fetch request, and more.

Table of Contents

  • 1. Intro to fetch()
  • 2. Fetching JSON
  • 3. Handling fetch errors
  • 4. Canceling a fetch request
  • 5. Parallel fetch requests
  • 6. Summary

1. Intro to fetch()

The Fetch API accesses resources across the network. You can make HTTP requests (using GET, POST and other methods), download, and upload files.

To start a request, call the special function fetch():


const response = await fetch(resource[, options]);


which accepts 2 arguments:

  • resource: the URL string, or a Request object
  • options: the configuration object with properties like method, headers, body, credentials, and more.

fetch() starts a request and returns a promise. When the request completes, the promise is resolved with the Response object. If the request fails due to some network problems, the promise is rejected.

async/await syntax fits great with fetch() because it simplifies the work with promises with syntactic sugar.

For example, let's make a request to fetch movies:


async function fetchMovies() {

const response = await fetch('/movies');

// waits until the request completes...

console.log(response);

}


fetchMovies() is an asynchronous function since it's marked with the async keyword.

await fetch('/movies') starts an HTTP request to '/movies' URL. Because the await keyword is present, the asynchronous function is paused until the request completes.

When the request completes, response is assigned with the response object of the request. Let's see in the next section how to extract useful data, like JSON or plain text, from the response.

2. Fetching JSON

The response object, returned by the await fetch(), is a generic placeholder for multiple data formats.

For example, you can extract the JSON object from a fetch response:


async function fetchMoviesJSON() {

const response = await fetch('/movies');

const movies = await response.json();

return movies;

}

fetchMoviesJSON().then(movies => {

movies; // fetched movies

});


response.json() is a method of the Response object that allows a JSON object to be extracted from the response. The method returns a promise, so you have to wait for the JSON: await response.json().

The Response object offers a lot of useful methods (all returning promises):

  • response.json() returns a promise resolved to a JSON object
  • response.text() returns a promise resolved to raw text
  • response.formData() returns a promise resolved to FormData
  • response.blob() returns a promise resolved to a Blob (a file-like object of raw data)
  • response.arrayBuffer()() returns a promise resolved to an ArryBuffer (raw generic binary data)

3. Handling fetch errors

When I was familiarizing with fetch(), I was surprised that fetch() doesn't throw an error when the server returns a bad HTTP status, e.g. client errors (400–499) or server errors (500–599).

For example, let's access a non-existing page '/oops' on the server. As expected, such request ends in a 404 response status:


async function fetchMovies404() {

const response = await fetch('/oops');

response.ok; // => false

response.status; // => 404

const text = await response.text();

return text;

}

fetchMovies404().then(text => {

text; // => 'Page not found'

});


When fetching the URL '/oops' the server responds with status 404 and text 'Page not found'. Surprisingly, fetch() doesn't throw an error for a missing URL, but considers this as a completed HTTP request.

fetch() rejects only if a request cannot be made or a response cannot be retrieved. This can happen during network problems: no internet connection, host not found, the server is not responding.

Fortunately, response.ok property lets you distinguish good from bad HTTP response statuses. The property is set to true only if the response has status 200-299.

In the above example, the response.ok property is false because the response has the status 404.

To throw an error on a bad HTTP status (outside of the range 200-299), check the value of response.ok property and throw an error manually:


async function fetchMoviesBadStatus() {

const response = await fetch('/oops');

if (!response.ok) {

const message = `An error has occured: ${response.status}`;

throw new Error(message);

}

const movies = await response.json();

return movies;

}

fetchMoviesBadStatus().catch(error => {

error.message; // 'An error has occurred: 404'

});


4. Canceling a fetch request

Unfortunately, fetch() API alone doesn't allow to cancel a fetch request once started. To cancel a fetch request you need an additional tool AbortController.

Connecting fetch() and AbortController requires 3 steps:


// Step 1: instantiate the abort controller

const controller = new AbortController();

// Step 2: make the fetch() aware of controller.signal

fetch(..., { signal: controller.signal });

// Step 3: call to cancel the request

controller.abort();


A) Before starting the request, create an abort controller instance: controller = new AbortController().

B) When starting the request properly, use the options argument of fetch(url, { signal: controller.signal }) and set signal property to be controller.signal.

C) Finally, if you need to cancel the request, just call controller.abort() method.

For example, let's implement 2 buttons that control a fetch request. Clicking the button Fetch movies starts a fetch() request, while clicking Cancel fetch aborts the request in progress:


let controller = null;

fetchMoviesButton.addEventListener('click', async () => {

controller = new AbortController();

try {

const response = await fetch('/movies', {

signal: controller.signal

});

} catch (error) {

console.log('Fetch error: ', error);

}

controller = null;

});

cancelFetchButton.addEventListener('click', () => {

if (controller) {

controller.abort();

}

});


Open the demo.

Open the demo. Click Fetch movies to start the request, then right away click Cancel fetch to cancel it. This makes the active request cancel: await fetch() gets rejected by throwing an abort error. The catch block then catches the abort error.

The abort controller instances are not reusable. Each time you start a fetch() request, you have to create a new abort controller instance for each request.

On a side note, if you'd like to timeout a fetch() request, follow my post How to Timeout a fetch() Request.

5. Parallel fetch requests

To perform parallel fetch requests use the Promise.all() helper function.

Let's start 2 parallel requests to fetch movies and categories:


async function fetchMoviesAndCategories() {

const [moviesResponse, categoriesResponse] = await Promise.all([

fetch('/movies'),

fetch('/categories')

]);

const movies = await moviesResponse.json();

const categories = await categoriesResponse.json();

return [movies, categories];

}

fetchMoviesAndCategories().then(([movies, categories]) => {

movies; // fetched movies

categories; // fetched categories

}).catch(error => {

// /movies or /categories request failed

});


await Promise.all([...]) starts fetch requests in parallel, and waits until all of them are resolved.

If any request fails, then the whole parallel promise gets rejected right away with the failed request error.

In case if you want all parallel requests to complete, despite any of them fail, consider using Promise.allSettled().

6. Summary

Calling fetch() starts a request and returns a promise. When the request completes, the promise resolves to the response object. From the response object you can extract data in the format you need: JSON, raw text, Blob.

Because fetch() returns a promise, you can simplify the code by using the async/await syntax: response = await fetch().

If you need to cancel a fetch() request, then you need to connect the request with an abort controller.

Having mastered the basics of fetch() with async/await, follow my post on How to Timeout a fetch() Request.

Still have questions on how to use fetch()? Write a question in the comments below!