JavaScript Crash Course
Асинхронність в JavaScript
9
Зміст:
-
Що таке асинхронність
-
Promise
-
Робота із запитами. Fetch API
-
Відловлювання помилок із try...catch
-
HTTP методи на статус коди
Що таке асинхронність?
Асинхронність
Це процес обробки введення/виводу, що дозволяє продовжити обробку інших завдань, не чекаючи завершення попереднього завдання.
Асинхронність в JS - це як шеф-повар, який може готувати декілька страв одночасно
А браузер - це офіціант, який буде приносити всі старви клієнту вчасно
Асинхронність в JS
Багато функцій, які надаються браузерами, і особливо найцікавіші з них, потенційно можуть зайняти багато часу, а тому є асинхронними. Наприклад:
- HTTP-запитів за допомогою fetch()
- доступ до камери або мікрофона користувача за допомогою getUserMedia()
- вібір файлів для доступу за допомогою showOpenFilePicker()
Promise
Що таке Promise?
Об’єкт Promise представляє можливе завершення (або збій) асинхронної операції та її результат.
Стани Promise
Promise може знаходиться в одному з таких станів:
- pending: початковий стан, не виконано і не відхилено.
- fulfilled: це означає, що операція була успішно завершена.
- rejected: це означає, що операція не вдалася.
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
myPromise
.then(handleResolvedA, handleRejectedA)
.then(handleResolvedB, handleRejectedB)
.then(handleResolvedC, handleRejectedC)
.catch(handleRejectedAny);
Оскільки методи Promise.prototype.then() і Promise.prototype.catch() повертають Promise, їх можна зв’язати(chained).
Метод Promise.all(iterable) повертає проміс, який виконається тоді, коли будуть виконані всі проміси, передані у вигляді аргументу, що перераховується, або відхилено будь-який з переданих промісів.
Promise.all()
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
Метод Promise.allSettled() повертає проміс, який виконується, коли всі отримані проміси завершені (виконані або відхилені), що містить масив результатів виконання отриманих промісів.
Promise.allSettled()
const promise1 = Promise.resolve(3);
const promise2 = new Promise(
(resolve, reject) => setTimeout(reject, 100, 'foo')
);
const promises = [promise1, promise2];
Promise.allSettled(promises)
.then((results) =>
results.forEach((result) => console.log(result.status))
);
// expected output:
// "fulfilled"
// "rejected"
const promise1 = Promise.reject(0);
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'quick'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'slow'));
const promises = [promise1, promise2, promise3];
Promise.any(promises).then((value) => console.log(value));
// expected output: "quick"
Promise.any() приймає ітерабельний об'єктів Promise і повертає перший успішний promise. Якщо жоден promise в ітерації не виконуються, то отримуємо AggregateError
Promise.any()
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// expected output: "two"
Метод Promise.any() приймає об'єкт, що містить об'єкти промісів Promise. Як тільки один із промісів (Promise) виконається успішно (fullfill), метод поверне єдиний об'єкт Promise зі значенням виконаного промісу. Якщо жоден із промісів не завершиться успішно (якщо всі проміси завершаться з помилкою, тобто rejected), тоді повернутий об'єкт Promise буде відхилений (rejected) з одним із значень: масив, що містить причини помилки (відхилення), або AggregateError — підклас Error що об'єднує викинуті помилки разом.
Promise.race()
Promise.reject(new Error('fail')).then(function() {
// not called
}, function(error) {
console.error(error); // Stacktrace
});
Метод Promise.reject(reason) повертає об'єкт Promise, який був відхилений з цієї причини.
Promise.reject()
Promise.resolve('Success').then(function(value) {
console.log(value); // "Success"
}, function(value) {
// not called
});
Метод Promise.resolve(value) повертає Promise виконаний із переданим значенням. Якщо передане значення є thenable - об'єкт (тобто має метод "then" method), повертається проміс буде слідувати thenable - об'єкту, приймаючи свій стан; в іншому випадку повертається проміс буде виконаний з переданим значенням.
Promise.resolve()
Робота із запитами. Fetch API
Взаємодія клієнт-сервер
user
website
server
взаємодія
HTTP запит
HTTP відповідь
Fetch API
Fetch API надає інтерфейс для отримання ресурсів (у тому числі через мережу). Він здасться знайомим будь-кому, хто використовував XMLHttpRequest, але новий API є більш потужним та гнучким набором функцій.
Fetch інтерфейс
Приклад
const USERS_URL = "https://api.github.com/users";
fetch(USERS_URL)
.then(response => response.json())
.then(result => console.log(result));
Приклад із відловленням помилки
const USERS_URL = "https://api.github.com/users";
fetch(USERS_URL)
.then(response => response.json())
.then(result => console.log(result))
.catch(error => {
// handle the error
console.error(error);
});
async ... await
Асинхронна функція — це функція, оголошена за допомогою ключового слова async, і ключового слова await. Ключові слова async і await дозволяють записати асинхронну поведінку на основі promise у більш чистому стилі, уникаючи необхідності явного налаштування ланцюжків promises.
Асинхронні функції також можуть бути визначені як вирази.
Приклад
async function fetchText() {
let response = await fetch('/readme.txt');
console.log(response.status); // 200
console.log(response.statusText); // OK
if (response.status === 200) {
let data = await response.text();
// handle data
}
}
fetchText();
Приклад
async function foo() {
return 1;
}
// it is similar to:
function foo() {
return Promise.resolve(1);
}
Приклад
function resolveAfter2Seconds() {
console.log("starting slow promise");
return new Promise((resolve) => {
setTimeout(() => {
resolve("slow");
console.log("slow promise is done");
}, 2000);
});
}
function resolveAfter1Second() {
console.log("starting fast promise");
return new Promise((resolve) => {
setTimeout(() => {
resolve("fast");
console.log("fast promise is done");
}, 1000);
});
}
async function sequentialStart() {
// 1. Execution gets here almost instantly
const slow = await resolveAfter2Seconds();
console.log(slow); // 2. this runs 2 seconds after 1.
const fast = await resolveAfter1Second();
console.log(fast); // 3. this runs 3 seconds after 1.
}
Відловлювання помилок із try...catch
try...catch
try {
throw new Error('oops');
} catch (ex) {
console.error('inner', ex.message);
} finally {
console.log('finally');
}
fetch + try...catch
fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error('Something went wrong');
})
.then((responseJson) => {
// Do something with the response
})
.catch((error) => {
console.log(error)
});
HTTP методи на статус коди
HTTP методи
GET
DELETE
POST
PUT
PATCH
OPTIONS
HTTP методи: GET
fetch("http://example.com/movies.json")
.then(res => res.json())
.then(resp => console.log(resp));
GET метод використовується для отримання даних
HTTP методи: POST
fetch("https://example.com/answer", {
method: "POST", // *GET, POST, PUT, DELETE, etc.
mode: "cors", // no-cors, *cors, same-origin
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "same-origin", // include, *same-origin, omit
headers: {
"Content-Type": "application/json",
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: "follow", // manual, *follow, error
referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, ...
body: JSON.stringify(data), // body data type must match "Content-Type" header
})
.then(res => res.json())
.then(resp => console.log(resp));
POST метод використовується для створення нових даних
HTTP методи: POST
fetch("https://example.com/answer", {
method: "POST", // *GET, POST, PUT, DELETE, etc.
mode: "cors", // no-cors, *cors, same-origin
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "same-origin", // include, *same-origin, omit
headers: {
"Content-Type": "application/json",
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: "follow", // manual, *follow, error
referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, ...
body: JSON.stringify({ answer: 42 }), // body data type must match "Content-Type"
})
.then(res => res.json())
.then(resp => console.log(resp));
POST метод використовується для створення нових даних
HTTP методи: PUT
fetch("https://example.com/answer", {
method: "PUT", // *GET, POST, PUT, DELETE, etc.
headers: {
"Content-Type": "application/json",
// 'Content-Type': 'application/x-www-form-urlencoded',
},
body: JSON.stringify({ answer: 42 }),
})
.then(res => res.json())
.then(resp => console.log(resp));
PUT метод використовується для оновлення існуючих даних
HTTP методи: PUT
async function upload(formData) {
try {
const response = await fetch("https://example.com/profile/avatar", {
method: "PUT",
body: formData,
});
const result = await response.json();
console.log("Success:", result);
} catch (error) {
console.error("Error:", error);
}
}
const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');
formData.append("username", "abc123");
formData.append("avatar", fileField.files[0]);
upload(formData);
PUT метод можна використовувати для завантаження даних:
HTTP методи: PATCH
fetch("https://example.com/answer", {
method: "PATCH", // *GET, POST, PUT, DELETE, etc.
headers: {
"Content-Type": "application/json",
// 'Content-Type': 'application/x-www-form-urlencoded',
},
body: JSON.stringify({ answer: 42 }),
})
.then(res => res.json())
.then(resp => console.log(resp));
PATCH метод використовується для часткового оновлення існуючих даних
HTTP методи: DELETE
fetch("https://example.com/answer/answer-id-1", {
method: "DELETE"
headers: {
"Content-Type": "application/json",
},
})
.then(res => res.json())
.then(resp => console.log(resp));
DELETE метод використовується для видалення існуючих даних
HTTP статус коди
201
404
200
409
403
401
500
302
HTTP статус коди
Виділяють п’ять класів:
- 1xx — інформаційні коди. Вони відповідають за процес передачі даних. Це тимчасові коди, котрі інформують про те, що запит прийнято і обробка буде продовжуватися.
- 2xx — успішна обробка. Запит було отримано та успішно оброблено сервером.
- 3xx — перенаправлення (редирект). Ці відповіді свідчать про те, що необхідно вжити подальших дій для виконання запиту. Наприклад, зробити запит на іншу адресу.
- 4xx — помилка клієнта. Означає, що запит не може бути виконаний з вини користувача.
- 5xx — помилка сервера. Ці коди виникають через помилки на стороні сервера. У цьому випадку користувач все зробив правильно, але сервер не може виконати запит. Для кодів цього класу сервер обов’язково показує повідомлення, що не може обробити запит і з якої причини.
HTTP статус коди
Основні:
- 200 — запит виконано успішно
- 301 — сторінка переміщена і виконується редирект
- 401 — аутентифікація HTTP не вдалася (Unauthorized)
- 403 — відмовлено в доступі (Forbidden)
- 404 — означає, що за вказаною URL нічого не знайдено (Not Found)
- 409 — спроба створити вже існуючі дані (Conflict)
- 500 — внутрішня помилка сервера (Іnternal Server Error)
- 503 — сервер тимчасово не може опрацьовувати запити з технічних причин (Service Unavailable)
- 504 — сервер працював як проксі і не дочекався відповіді від вищого сервера для завершення запиту (Gateway Timeout)
Q & A
_11 JavaScript Crash Course
By Inna Ivashchuk
_11 JavaScript Crash Course
- 477