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));
example that can be executed in the browser console:
// request a URL and wait for the response header
res = await fetch(
'https://jsonplaceholder.typicode.com/todos'
);
// wait for the response body and read it as JSON data
content = await res.json();
console.log(content);
example that can be executed in the browser console with any open website:
// request the current URL
res = await fetch("/");
// wait for the response body and read its text content
content = await res.text();
console.log(content);
Functions that perform input / output functionality are often declared as asynchronous functions.
Asynchronous functions can run in parallel to other code: E.g. for loading multiple files over the network in parallel.
defining an asynchronous function:
async function loadTodo(id) {
const res = await fetch(
`https://jsonplaceholder.typicode.com/todos/${id}`
);
const data = await res.json();
return data;
}
run the asynchronous function in parallel multiple times (you can watch the requests in your browser console):
for (let i = 0; i < 10; i++) {
loadTodo(i);
}
example of a fetch call with some options:
fetch(url, {
method: 'POST',
cache: 'no-cache',
body: '{"text": "learn fetch"}',
headers: { 'content-type': 'application/json' },
});
various errors may occur when fetching data:
by default a reply with an error code (e.g. 404 or 500) is considered a success
async function fetchTodos () => {
const res = await fetch(
'https://jsonplaceholder.typicode.com/todos'
);
if (!res.ok) {
throw new Error(res.statusText);
}
const todos = await res.json();
return todos;
};
Promise: JavaScript class that represents future results
Promises are used internally when async
/ await
is used
we can access promises if we "forget" to await an asynchronous result:
// a will be a promise
const a = fetch('...');
// b will be the actual result
const b = await a;
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 to resolve:
await
.then()
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:
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);