update promises
This commit is contained in:
74
docs/javascript/07-errors/01-try-catch.md
Normal file
74
docs/javascript/07-errors/01-try-catch.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# Обработка ошибок, "try..catch"
|
||||||
|
Конструкция `try..catch` позволяет обрабатывать ошибки во время исполнения кода. Она позволяет запустить код и перехватить ошибки, которые могут в нём возникнуть.
|
||||||
|
|
||||||
|
Секций `catch` или `finally` может не быть, то есть более короткие конструкции `try..catch` и `try..finally` также корректны.
|
||||||
|
|
||||||
|
Объекты ошибок содержат следующие свойства:
|
||||||
|
- `message` – понятное человеку сообщение.
|
||||||
|
- `name` – строка с именем ошибки (имя конструктора ошибки).
|
||||||
|
- `stack` (нестандартное, но хорошо поддерживается) – стек на момент ошибки.
|
||||||
|
|
||||||
|
Если объект ошибки не нужен, мы можем пропустить его, используя `catch {` вместо `catch(err) {`.
|
||||||
|
|
||||||
|
Мы можем также генерировать собственные ошибки, используя оператор `throw`. Аргументом `throw` может быть что угодно, но обычно это объект ошибки, наследуемый от встроенного класса `Error`. Подробнее о расширении ошибок см. в следующей главе.
|
||||||
|
|
||||||
|
Проброс исключения – это очень важный приём обработки ошибок: блок `catch` обычно ожидает и знает, как обработать определённый тип ошибок, поэтому он должен пробрасывать дальше ошибки, о которых он не знает.
|
||||||
|
|
||||||
|
Даже если у нас нет `try..catch`, большинство сред позволяют настроить «глобальный» обработчик ошибок, чтобы ловить ошибки, которые «выпадают наружу». В браузере это window.onerror.
|
||||||
|
|
||||||
|
**`try..catch` работает синхронно**
|
||||||
|
|
||||||
|
|
||||||
|
## try…catch…finally
|
||||||
|
```js
|
||||||
|
try {
|
||||||
|
//... пробуем выполнить код...
|
||||||
|
} catch(e) {
|
||||||
|
//... обрабатываем ошибки ...
|
||||||
|
} finally {
|
||||||
|
//... выполняем всегда ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Оператор «throw»
|
||||||
|
Оператор throw генерирует ошибку.
|
||||||
|
|
||||||
|
```js
|
||||||
|
let json = '{ "age": 30 }'; // данные неполны
|
||||||
|
try {
|
||||||
|
let user = JSON.parse(json); // <-- выполнится без ошибок
|
||||||
|
if (!user.name) {
|
||||||
|
throw new SyntaxError("Данные неполны: нет имени"); // (*)
|
||||||
|
}
|
||||||
|
alert( user.name );
|
||||||
|
} catch(e) {
|
||||||
|
alert( "JSON Error: " + e.message ); // JSON Error: Данные неполны: нет имени
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Проброс исключения
|
||||||
|
Блок `catch` должен обрабатывать только те ошибки, которые ему известны, и «пробрасывать» все остальные.
|
||||||
|
|
||||||
|
Техника «проброс исключения» выглядит так:
|
||||||
|
1. Блок `catch` получает все ошибки.
|
||||||
|
2. В блоке `catch(err) {...}` мы анализируем объект ошибки `err`.
|
||||||
|
3. Если мы не знаем как её обработать, тогда делаем `throw err`.
|
||||||
|
|
||||||
|
## Глобальный catch
|
||||||
|
Давайте представим, что произошла фатальная ошибка (программная или что-то ещё ужасное) снаружи try..catch, и скрипт упал.
|
||||||
|
|
||||||
|
Существует ли способ отреагировать на такие ситуации? Мы можем захотеть залогировать ошибку, показать что-то пользователю (обычно они не видят сообщение об ошибке) и т.д.
|
||||||
|
|
||||||
|
В Node.js для этого есть process.on("uncaughtException"). А в браузере мы можем присвоить функцию специальному свойству window.onerror, которая будет вызвана в случае необработанной ошибки.
|
||||||
|
```js
|
||||||
|
window.onerror = function(message, url, line, col, error) {
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
- **message** - Сообщение об ошибке.
|
||||||
|
- **url** - URL скрипта, в котором произошла ошибка.
|
||||||
|
- **line**, col - Номера строки и столбца, в которых произошла ошибка.
|
||||||
|
- **error** - Объект ошибки.
|
||||||
11
docs/javascript/07-errors/02-extend-errors.md
Normal file
11
docs/javascript/07-errors/02-extend-errors.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
# Пользовательские ошибки, расширение Error
|
||||||
|
Источник: [https://learn.javascript.ru/custom-errors](https://learn.javascript.ru/custom-errors)
|
||||||
|
|
||||||
|
- Мы можем наследовать свои классы ошибок от `Error` и других встроенных классов ошибок, но нужно позаботиться о свойстве name и не забыть вызвать `super`.
|
||||||
|
- Мы можем использовать `instanceof` для проверки типа ошибок. Это также работает с наследованием. Но иногда у нас объект ошибки, возникшей в сторонней библиотеке, и нет простого способа получить класс. Тогда для проверки типа ошибки можно использовать свойство `name`.
|
||||||
|
- Обёртывание исключений является распространённой техникой: функция ловит низкоуровневые исключения и создаёт одно «высокоуровневое» исключение вместо разных низкоуровневых. Иногда низкоуровневые исключения становятся свойствами этого объекта, как `err.cause` в примерах выше, но это не обязательно.
|
||||||
|
|
||||||
46
docs/javascript/08-promises/01-callbacks.md
Normal file
46
docs/javascript/08-promises/01-callbacks.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# Введение: колбэки
|
||||||
|
Источник *Deepseek*
|
||||||
|
|
||||||
|
Асинхронное программирование с использованием callback-функций в JavaScript — это один из традиционных подходов для работы с асинхронными операциями, такими как чтение файлов, запросы к серверу или таймеры. Callback-функция передается в качестве аргумента в асинхронную функцию и вызывается после завершения этой операции.
|
||||||
|
|
||||||
|
Вот пример асинхронного программирования с использованием callback:
|
||||||
|
```js
|
||||||
|
// Пример асинхронной функции, которая имитирует запрос к серверу
|
||||||
|
function fetchData(callback) {
|
||||||
|
// Имитируем задержку с помощью setTimeout
|
||||||
|
setTimeout(() => {
|
||||||
|
const data = { name: "John", age: 30 };
|
||||||
|
// Вызываем callback-функцию и передаем ей данные
|
||||||
|
callback(data);
|
||||||
|
}, 2000); // Задержка 2 секунды
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback-функция, которая будет вызвана после получения данных
|
||||||
|
function handleData(data) {
|
||||||
|
console.log("Данные получены:", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вызов асинхронной функции с передачей callback
|
||||||
|
fetchData(handleData);
|
||||||
|
|
||||||
|
console.log("Ожидание данных...");
|
||||||
|
```
|
||||||
|
|
||||||
|
Объяснение:
|
||||||
|
1. **fetchData** — это асинхронная функция, которая имитирует запрос к серверу с задержкой в 2 секунды.
|
||||||
|
2. **callback** — это функция, которая передается в `fetchData` и будет вызвана после завершения асинхронной операции.
|
||||||
|
3. **handleData** — это callback-функция, которая обрабатывает полученные данные.
|
||||||
|
4. **setTimeout** используется для имитации задержки, как будто данные загружаются с сервера.
|
||||||
|
|
||||||
|
Вывод в консоль:
|
||||||
|
```
|
||||||
|
Ожидание данных...
|
||||||
|
Данные получены: { name: "John", age: 30 }
|
||||||
|
```
|
||||||
|
Особенности:
|
||||||
|
- Callback-функции могут привести к так называемому "callback hell" (ад колбэков), когда много асинхронных операций вложены друг в друга, что делает код сложным для чтения и поддержки.
|
||||||
|
- В современных JavaScript-проектах вместо callback-функций часто используют Promises или async/await для более удобной работы с асинхронным кодом.
|
||||||
85
docs/javascript/08-promises/02-promises.md
Normal file
85
docs/javascript/08-promises/02-promises.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
# Promises
|
||||||
|
Источник *Deepseek*
|
||||||
|
|
||||||
|
Использование Promises (обещаний) в JavaScript — это более современный и удобный способ работы с асинхронными операциями по сравнению с callback-функциями. Promises позволяют избежать "callback hell" и делают код более читаемым и структурированным.
|
||||||
|
|
||||||
|
Вот пример асинхронного программирования с использованием Promises:
|
||||||
|
```js
|
||||||
|
// Пример асинхронной функции, которая возвращает Promise
|
||||||
|
function fetchData() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// Имитируем задержку с помощью setTimeout
|
||||||
|
setTimeout(() => {
|
||||||
|
const success = true; // Имитируем успешное выполнение или ошибку
|
||||||
|
if (success) {
|
||||||
|
const data = { name: "Alice", age: 25 };
|
||||||
|
resolve(data); // Успешное выполнение
|
||||||
|
} else {
|
||||||
|
reject("Ошибка: Данные не получены"); // Ошибка
|
||||||
|
}
|
||||||
|
}, 2000); // Задержка 2 секунды
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Использование Promise
|
||||||
|
fetchData()
|
||||||
|
.then((data) => {
|
||||||
|
console.log("Данные получены:", data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
console.log("Запрос завершен.");
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Ожидание данных...");
|
||||||
|
```
|
||||||
|
Объяснение:
|
||||||
|
1. **fetchData** — это функция, которая возвращает `Promise`. Внутри `Promise` выполняется асинхронная операция (в данном случае, с задержкой в 2 секунды).
|
||||||
|
2. **resolve** — вызывается, если операция завершилась успешно. В этом случае `Promise` переходит в состояние "fulfilled" (выполнено), и данные передаются в метод .then().
|
||||||
|
3. **reject** — вызывается, если произошла ошибка. В этом случае `Promise` переходит в состояние "rejected" (отклонено), и ошибка передается в метод .catch().
|
||||||
|
4. **.then()** — обрабатывает успешный результат.
|
||||||
|
5. **.catch()** — обрабатывает ошибки.
|
||||||
|
6. **.finally()** — выполняется в любом случае, независимо от того, завершился `Promise` успешно или с ошибкой.
|
||||||
|
|
||||||
|
#### Вывод в консоль:
|
||||||
|
```
|
||||||
|
Ожидание данных...
|
||||||
|
Данные получены: { name: "Alice", age: 25 }
|
||||||
|
Запрос завершен.
|
||||||
|
```
|
||||||
|
#### Если произойдет ошибка:
|
||||||
|
Если переменная `success` будет равна `false`, то вывод будет таким:
|
||||||
|
```
|
||||||
|
Ожидание данных...
|
||||||
|
Ошибка: Данные не получены
|
||||||
|
Запрос завершен.
|
||||||
|
```
|
||||||
|
#### Преимущества Promises:
|
||||||
|
- Более читаемый и структурированный код.
|
||||||
|
- Легко комбинировать несколько асинхронных операций с помощью `.then()`.
|
||||||
|
- Удобная обработка ошибок через `.catch()`.
|
||||||
|
|
||||||
|
#### Пример с цепочкой Promises:
|
||||||
|
```js
|
||||||
|
fetchData()
|
||||||
|
.then((data) => {
|
||||||
|
console.log("Данные получены:", data);
|
||||||
|
return data.age; // Возвращаем только возраст
|
||||||
|
})
|
||||||
|
.then((age) => {
|
||||||
|
console.log("Возраст пользователя:", age);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
Этот пример показывает, как можно последовательно обрабатывать данные с помощью цепочки `.then()`.
|
||||||
|
|
||||||
|
💥 **Thenable**
|
||||||
|
> Если быть более точными, обработчик может возвращать не именно промис, а любой объект, содержащий метод .then, такие объекты называют «thenable», и этот объект будет обработан как промис.
|
||||||
52
docs/javascript/08-promises/03-promises-error.md
Normal file
52
docs/javascript/08-promises/03-promises-error.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# Обработка ошибок
|
||||||
|
Источник: [https://learn.javascript.ru/promise-error-handling](https://learn.javascript.ru/promise-error-handling)
|
||||||
|
|
||||||
|
- `.catch` перехватывает все виды ошибок в промисах: будь то вызов `reject()` или ошибка, брошенная в обработчике при помощи `throw`.
|
||||||
|
- `.then` также перехватывает ошибки таким же образом, если задан второй аргумент (который является обработчиком ошибок).
|
||||||
|
- Необходимо размещать `.catch` там, где мы хотим обработать ошибки и знаем, как это сделать. Обработчик может проанализировать ошибку (могут быть полезны пользовательские классы ошибок) и пробросить её, если ничего не знает о ней (возможно, это программная ошибка).
|
||||||
|
- Можно и совсем не использовать `.catch`, если нет нормального способа восстановиться после ошибки.
|
||||||
|
- В любом случае нам следует использовать обработчик события `u`nhandledrejection` (для браузеров и аналог для других окружений), чтобы отслеживать необработанные ошибки и информировать о них пользователя (и, возможно, наш сервер), благодаря чему наше приложение никогда не будет «просто умирать».
|
||||||
|
|
||||||
|
## Неявный try…catch
|
||||||
|
Вокруг функции промиса и обработчиков находится `«невидимый try..catch»`. Если происходит исключение, то оно перехватывается, и промис считается отклонённым с этой ошибкой.
|
||||||
|
|
||||||
|
«Невидимый try..catch» вокруг промиса автоматически перехватывает ошибку и превращает её в отклонённый промис.
|
||||||
|
|
||||||
|
Это работает не только в функции промиса, но и в обработчиках. Если мы бросим ошибку (throw) из обработчика (.then), то промис будет считаться отклонённым, и управление перейдёт к ближайшему обработчику ошибок.
|
||||||
|
|
||||||
|
## Пробрасывание ошибок
|
||||||
|
Мы можем иметь столько обработчиков `.then`, сколько мы хотим, и затем использовать один `.catch` в конце, чтобы перехватить ошибки из всех обработчиков.
|
||||||
|
|
||||||
|
В обычном `try..catch` мы можем проанализировать ошибку и повторно пробросить дальше, если не можем её обработать. То же самое возможно для промисов.
|
||||||
|
|
||||||
|
Если мы пробросим `(throw)` ошибку внутри блока `.catch`, то управление перейдёт к следующему ближайшему обработчику ошибок. А если мы обработаем ошибку и завершим работу обработчика нормально, то продолжит работу ближайший успешный обработчик `.then`.
|
||||||
|
|
||||||
|
## Необработанные ошибки
|
||||||
|
Что произойдёт, если ошибка не будет обработана? \
|
||||||
|
В случае ошибки выполнение должно перейти к ближайшему обработчику ошибок.
|
||||||
|
|
||||||
|
Что происходит, когда обычная ошибка не перехвачена try..catch? Скрипт умирает с сообщением в консоли. Похожее происходит и в случае необработанной ошибки промиса.
|
||||||
|
|
||||||
|
JavaScript-движок отслеживает такие ситуации и генерирует в этом случае глобальную ошибку. Вы можете увидеть её в консоли, если запустите пример выше.
|
||||||
|
|
||||||
|
В браузере мы можем поймать такие ошибки, используя событие unhandledrejection:
|
||||||
|
```js
|
||||||
|
window.addEventListener('unhandledrejection', function(event) {
|
||||||
|
// объект события имеет два специальных свойства:
|
||||||
|
alert(event.promise); // [object Promise] - промис, который сгенерировал ошибку
|
||||||
|
alert(event.reason); // Error: Ошибка! - объект ошибки, которая не была обработана
|
||||||
|
});
|
||||||
|
|
||||||
|
new Promise(function() {
|
||||||
|
throw new Error("Ошибка!");
|
||||||
|
}); // нет обработчика ошибок
|
||||||
|
```
|
||||||
|
|
||||||
|
Если происходит ошибка, и отсутствует её обработчик, то генерируется событие `unhandledrejection`, и соответствующий объект `event` содержит информацию об ошибке.
|
||||||
|
|
||||||
|
Обычно такие ошибки неустранимы, поэтому лучше всего – информировать пользователя о проблеме и, возможно, отправить информацию об ошибке на сервер.
|
||||||
|
|
||||||
18
docs/javascript/08-promises/04-promise-api.md
Normal file
18
docs/javascript/08-promises/04-promise-api.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 4
|
||||||
|
---
|
||||||
|
|
||||||
|
# Promise API
|
||||||
|
Источник:
|
||||||
|
В классе Promise есть 6 статических методов.
|
||||||
|
|
||||||
|
- **Promise.all(promises)** – ожидает выполнения всех промисов и возвращает массив с результатами. Если любой из указанных промисов вернёт ошибку, то результатом работы Promise.all будет эта ошибка, результаты остальных промисов будут игнорироваться.
|
||||||
|
- **Promise.allSettled(promises)** (добавлен недавно) – ждёт, пока все промисы завершатся и возвращает их результаты в виде массива с объектами, у каждого объекта два свойства:
|
||||||
|
- status: "fulfilled", если выполнен успешно или "rejected", если ошибка,
|
||||||
|
- value – результат, если успешно или reason – ошибка, если нет.
|
||||||
|
- **Promise.race(promises)** – ожидает первый выполненный промис, который становится его результатом, остальные игнорируются.
|
||||||
|
- **Promise.any(promises)** (добавлен недавно) – ожидает первый успешно выполненный промис, который становится его результатом, остальные игнорируются. Если все переданные промисы отклонены, AggregateError становится ошибкой `Promise.any`.
|
||||||
|
- **Promise.resolve(value)** – возвращает успешно выполнившийся промис с результатом value.
|
||||||
|
- **Promise.reject(error)** – возвращает промис с ошибкой error.
|
||||||
|
|
||||||
|
Из всех перечисленных методов, самый часто используемый – **Promise.all**.
|
||||||
41
docs/javascript/08-promises/05-promisification.md
Normal file
41
docs/javascript/08-promises/05-promisification.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 5
|
||||||
|
---
|
||||||
|
|
||||||
|
# Промисификация
|
||||||
|
Источник: [https://learn.javascript.ru/promisify](https://learn.javascript.ru/promisify)
|
||||||
|
|
||||||
|
Промисификация – это длинное слово для простого преобразования. Мы берём функцию, которая принимает колбэк и меняем её, чтобы она вместо этого возвращала промис.
|
||||||
|
|
||||||
|
Такие преобразования часто необходимы в реальной жизни, так как многие функции и библиотеки основаны на колбэках, а использование промисов более удобно, поэтому есть смысл «промисифицировать» их.
|
||||||
|
|
||||||
|
💥 **На заметку:**
|
||||||
|
- Промисификация – это отличный подход, особенно, если вы будете использовать async/await (см. следующую главу об Async/await) но она не является тотальной заменой любых колбэков.
|
||||||
|
- Помните, промис может иметь только один результат, но колбэк технически может вызываться сколько угодно раз.
|
||||||
|
- Поэтому промисификация используется для функций, которые вызывают колбэк только один раз. Последующие вызовы колбэка будут проигнорированы.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// promisify(f, true), чтобы получить массив результатов
|
||||||
|
function promisify(f, manyArgs = false) {
|
||||||
|
return function (...args) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
function callback(err, ...results) { // наш специальный колбэк для f
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
// делаем resolve для всех results колбэка, если задано manyArgs
|
||||||
|
resolve(manyArgs ? results : results[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push(callback);
|
||||||
|
|
||||||
|
f.call(this, ...args);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// использование:
|
||||||
|
f = promisify(f, true);
|
||||||
|
f(...).then(arrayOfResults => ..., err => ...)
|
||||||
|
```
|
||||||
19
docs/javascript/08-promises/06-acync-await.md
Normal file
19
docs/javascript/08-promises/06-acync-await.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 6
|
||||||
|
---
|
||||||
|
|
||||||
|
# Async/await
|
||||||
|
|
||||||
|
По сути, это просто «синтаксический сахар» для получения результата промиса, более наглядный, чем `promise.then`.
|
||||||
|
|
||||||
|
Ключевое слово `async` перед объявлением функции:
|
||||||
|
1. Обязывает её всегда возвращать промис.
|
||||||
|
2. Позволяет использовать await в теле этой функции.
|
||||||
|
|
||||||
|
Ключевое слово `await` перед промисом заставит JavaScript дождаться его выполнения, после чего:
|
||||||
|
1. Если промис завершается с ошибкой, будет сгенерировано исключение, как если бы на этом месте находилось `throw`.
|
||||||
|
2. Иначе вернётся результат промиса.
|
||||||
|
|
||||||
|
Вместе они предоставляют отличный каркас для написания асинхронного кода. Такой код легко и писать, и читать.
|
||||||
|
|
||||||
|
Хотя при работе с `async/await` можно обходиться без `promise.then/catch`, иногда всё-таки приходится использовать эти методы (на верхнем уровне вложенности, например). Также `await` отлично работает в сочетании с `Promise.all`, если необходимо выполнить несколько задач параллельно.
|
||||||
Reference in New Issue
Block a user