Handbooks / JavaScript / Chapter 10
Browser APIs: fetch and Storage
7 pages · ~4 min✓ Reviewed
Builds on DOM and Events.
Fetch Mental Model and Options
1. What fetch returns
- fetch(url, options)call
- Promise<Response>resolves on headers
- Body streamread later
- Promise resolves once headers arrive
- The body is a separate stream read later
- Options:
method(default GET),headers,body,credentials,mode,cache,signal
2. POST JSON
javascript
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})stringify the object yourself
- Body must be a string,
FormData,BloborURLSearchParams - A raw object becomes "[object Object]"
3. credentials
| Value | Cookies sent |
|---|---|
'same-origin' (default) | Same origin only |
'include' | Also cross-origin |
'omit' | Never |
response.ok, Status and Parsing JSON
1. Check response.ok
- fetch rejects only on network failure or abort
- HTTP 404/500 still resolve
res.okis true for status 200-299
javascript
const res = await fetch(u); if (!res.ok) throw new Error(res.status); const data = await res.json();
check ok before parsing
2. Body Parsers
| Method | Gives |
|---|---|
res.json() | parsed JSON |
res.text() | string |
res.blob() |
AbortController and Timeouts
1. Cancel a request
ctrl.signalgoes into fetch; ctrl.abort() cancels the request- Aborted fetch rejects with
AbortError - Ignore the abort names; rethrow real errors
javascript
const ctrl = new AbortController(); fetch(url, { signal: ctrl.signal }).catch(e => { if (e.name === 'AbortError' || e.name === 'TimeoutError') return; throw e; }); ctrl.abort();
2. Timeout and combine
| Signal | Rejects with |
|---|---|
ctrl.abort() | AbortError |
AbortSignal.timeout(5000) |
localStorage vs sessionStorage vs Cookies
1. Lifetime and scope
| localStorage | sessionStorage | Cookies | |
|---|---|---|---|
| Lifetime | Until cleared | One tab, gone on close | Expires / Max-Age |
| Scope | All tabs, one origin | That tab only | Origin + Path |
| Size | ~5MB | ~5MB | ~4KB |
| Sent to server | No | No | Every request |
IndexedDB Basics
1. Workflow
- Async, transactional key-value object store
- Holds objects, Blobs, files: hundreds of MB+
- openname, version
- onupgradeneededschema here
- transactionreadwrite
- put / getobjectStore
javascript
const req = indexedDB.open('app', 2); req.onupgradeneeded = () => { req.result.createObjectStore('users', { keyPath: 'id' }) .createIndex('byName', 'name'); }; req.onsuccess = () => req.result .transaction('users', 'readwrite') .objectStore('users').put({ id: 1, name: 'Ana' });
schema in upgrade, data in a transaction
- Schema changes only in onupgradeneeded
- It runs only after a bumped version
URL, URLSearchParams and Cheat Sheet
1. Parse a URL
new URL(path, base)resolves a relative path against base- Properties:
origin,pathname,search,hash,searchParams - An invalid URL throws TypeError
searchParams.setencodes the value for you
javascript
const url = new URL('/api?q=a', 'https://x.com'); url.searchParams.set('q', 'a b&c'); console.log(url.origin, url.pathname, url.search);
output
https://x.com /api ?q=a+b%26c
2. URLSearchParams
| Method | Effect |
|---|---|
get(k) |
Check yourself
The server returns 404. Does const res = await fetch('/missing') throw?
- No.
fetchrejects only on network failure or abort. - The Promise resolves with
res.ok === false, so checkres.okbeforeres.json().
What happens with await res.json(); await res.text(); on the same response?
- The second call rejects with a TypeError, because the body stream is already used (
bodyUsedis true). - Call
res.clone()before the first read.
After localStorage.setItem('user', {name:'Ann'}), what does JSON.parse(localStorage.getItem('user')) do?
- It throws. The stored value is the string "[object Object]", which is not valid JSON.