some tasks in JavaScript may be scheduled to run in parallel (in particular tasks related to input/output):
possibilities for making network requests:
examples: requests with axios (await), axios (then) and jQuery (callback):
const res = await axios(url);
console.log(res.data);
axios(url).then((res) => console.log(res.data));
jquery.getJSON(url, (data) => console.log(data));
Promise: representation of a future result that is not available immediately
real-world example:
You place an order at a fast food restaurant. The cashier hands you this receipt:
order #42:
- cheeseburger
- small fries
The order will be served to you at your seat when ready.
the receipt is a "promise" - a representation of a future result
waiting for a promise is non-blocking: other code may be executed while waiting for the result
waiting for a promise to resolve:
.then()
await
// request the home page (/)
fetch('/')
// wait for a response, then request its text content
.then((res) => res.text())
// wait for the text content, then log it
.then((content) => console.log(content));
may be executed in the browser console for any open website
Fetching a URL and reading the response text may both take some time.
By using .then()
we can wait for their respective results.
The method .then()
will receive another function which will act as a handler for the response.
The first handler ((res) => res.text()
) will result in another Promise.
The second handler ((content) => console.log(content)
) will log the results.
example: fetching JSON data - two functions that return promises
const fetchTodos = () => {
return fetch(
'https://jsonplaceholder.typicode.com/todos'
).then((res) => res.json());
};
const fetchTodos = async () => {
const res = await fetch(
'https://jsonplaceholder.typicode.com/todos'
);
const todos = await res.json();
return todos;
};
As per the current ES standard, an await
statement always has to be inside an async
function
state of "top level await" (await outside of async functions):
advantages of await
:
advantages of .then
:
fetch(url, {
method: 'POST',
cache: 'no-cache',
body: '{"text": "learn fetch"}',
headers: { 'content-type': 'application/json' },
});
various errors may occur when fetching data:
catching any errors that might have occured:
fetch('https://jsonplaceholder.typicode.com/todos')
.then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.log(err));
by default a reply with an error code (e.g. 404 or 500) is considered a success
const fetchTodos = async () => {
const res = await fetch(
'https://jsonplaceholder.typicode.com/todos'
);
if (!res.ok) {
throw new Error(res.statusText);
}
const todos = await res.json();
return todos;
};
A promise that, after 1 second, either results in the string 'hello'
or fails
const getReply = new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve('hello');
} else {
reject('no access');
}
}, 1000);
});
Creating a promise that resolves when multiple asynchronous tasks have been completed:
const fetchJson = async (url) => {
const res = await fetch(url);
return await res.json();
};
const [users, todos] = await Promise.all([
fetchJson('https://jsonplaceholder.typicode.com/users'),
fetchJson('https://jsonplaceholder.typicode.com/todos'),
]);
Use the first successful promise as the result:
const anyTodo = await Promise.race([
fetchJson('https://jsonplaceholder.typicode.com/todos/1'),
fetchJson('https://jsonplaceholder.typicode.com/todos/2'),
fetchJson('https://jsonplaceholder.typicode.com/todos/3'),
]);
widely used library that provides more functionality / a simpler interface than fetch
Fetching JSON data:
const todos = await axios(
'https://jsonplaceholder.typicode.com/todos'
);
default behavior:
fetch('https://jsonplaceholder.typicode.com/todos')
.then(res => res.json())
.then(data => console.log(data));
import axios from 'axios';
axios('https://jsonplaceholder.typice.com/todos')
.then(res => console.log(res.data));
fetch('https://www.w3.org')
.then(res => res.text())
.then(content => console.log(content));
axios('https://www.w3.org', { responseType: 'text' })
.then(content => console.log(content));
Warning: By default axios will at least try to parse as JSON
fetch('https://jsonplaceholder.typicode.com/todos', {
method: 'post',
body: '{"title": "xyz"}',
headers: { 'Content-Type': 'application/json' },
});
axios.post(
'https://jsonplaceholder.typicode.com/todos',
'{"title": "xyz"}',
{ headers: { 'Content-Type': 'application/json' } }
);
const query = '{pokemon(name: "Pikachu") {number name}}';
const body = JSON.stringify({ query: query });
fetch('https://graphql-pokemon.now.sh', {
method: 'post',
body: body,
headers: { 'Content-Type': 'application/json' },
})
.then(res => res.json())
.then(data => console.log(data.data));
const query = '{pokemon(name: "Pikachu") {number name}}';
const body = JSON.stringify({ query: query });
axios
.post('https://graphql-pokemon.now.sh', body, {
headers: { 'Content-Type': 'application/json' },
})
.then(res => console.log(res.data.data));
examples:
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] =
'application/x-www-form-urlencoded';
const todosAxios = axios.create({
baseURL: 'https://jsonplaceholder.typicode.com/todos',
timeout: 2000,
});
todosAxios.get('/').then(console.log);
todosAxios.get('/1').then(console.log);
Interceptors may be added to the configuration; they are called automatically on either requests or responses and can contain additional logic to modify them
const requestLogger = requestConfig => {
console.log('sending request', requestConfig);
return requestConfig;
};
todosAxios.interceptors.request.use(requestLogger);
const responseLogger = response => {
console.log('received response', response);
return response;
};
todosAxios.interceptors.request.use(responseLogger);