|
3 | 3 | ## Решить задачи на асинхронность
|
4 | 4 |
|
5 | 5 | - в репозитории прошлого задания сделать новую ветку
|
6 |
| -- решить предложенный набор задач (@todo) (и покрыть их тестами от 50%) |
| 6 | +- решить предложенный набор задач (и покрыть их тестами от 50%) |
7 | 7 | - открыть PR с релеватными изменениямяи (без лишних задач)
|
8 | 8 | - сделать ревью 1 PR другого студента
|
9 | 9 |
|
| 10 | +## Задачи |
| 11 | + |
| 12 | +### Promisify |
| 13 | + |
| 14 | +Вам необходимо написать функцию promisify, которая преобразует функцию с колбэком в функцию, возвращающую промис. Это позволит работать с асинхронными функциями в современном стиле, используя промисы вместо колбэков. |
| 15 | + |
| 16 | +Требования: |
| 17 | + |
| 18 | +- Функция promisify принимает на вход функцию, которая ожидает колбэк последним аргументом. Колбэк должен иметь стандартный вид: callback(error, result). |
| 19 | +- promisify возвращает новую функцию. При вызове эта функция возвращает промис, который: |
| 20 | + - Резолвится с результатом, если в колбэк передан null или undefined вместо ошибки. |
| 21 | + - Реджектится, если в колбэк передана ошибка. |
| 22 | +- Ваша функция должна корректно передавать все аргументы исходной функции, кроме колбэка. |
| 23 | + |
| 24 | +```js |
| 25 | +// Пример функции на колбэках |
| 26 | +function sum(a, b, cb) { |
| 27 | + setTimeout(() => { |
| 28 | + if (Math.random() < 0.5) { |
| 29 | + cb(null, a + b); // успех |
| 30 | + } else { |
| 31 | + cb("Ошибка"); // ошибка |
| 32 | + } |
| 33 | + }, 100); |
| 34 | +} |
| 35 | + |
| 36 | +// Преобразуем с помощью promisify |
| 37 | +const promisifiedSum = promisify(sum); |
| 38 | + |
| 39 | +promisifiedSum(2, 3) |
| 40 | + .then(result => console.log(result)) // 5 |
| 41 | + .catch(err => console.log(err)); // "Ошибка" |
| 42 | +``` |
| 43 | + |
| 44 | +### Parallel |
| 45 | + |
| 46 | +Реализуйте класс `Parallel`, который позволяет запускать несколько асинхронных задач (job) параллельно с ограничением на максимальное количество одновременно выполняющихся задач. |
| 47 | + |
| 48 | +**Требования:** |
| 49 | + |
| 50 | +- Класс должен называться `Parallel` и быть конструктором (использоваться через `new`). |
| 51 | + |
| 52 | +- У экземпляра должны быть публичные методы: |
| 53 | + - `job(fn)` — добавляет задачу (функцию), которую нужно выполнить. Метод должен поддерживать чейнинг (возвращать сам объект). |
| 54 | + |
| 55 | + - `done(cb)` — запускает выполнение всех добавленных задач. Когда все задачи завершены, вызывает колбэк `cb`, передавая ему массив результатов. |
| 56 | + |
| 57 | +- Если не было добавлено ни одной задачи, `done` должен вызываться асинхронно. |
| 58 | + |
| 59 | +- Пока не вызван `done`, задачи не запускаются. |
| 60 | + |
| 61 | +- Если при создании объекта передать число (например, `new Parallel(3)`), оно задаёт максимальное количество задач, которые могут выполняться одновременно. |
| 62 | + |
| 63 | +- Все задачи — функции, которые принимают один аргумент: функцию-колбэк `done(result)`, которую нужно вызвать по завершении задачи. |
| 64 | + |
| 65 | +- Результаты должны возвращаться в том же порядке, в котором были добавлены задачи. |
| 66 | + |
| 67 | +- Продумайте выполнение задач без простоев |
| 68 | + |
| 69 | +```js |
| 70 | +const runner = new Parallel(2); |
| 71 | + |
| 72 | +runner |
| 73 | + .job(done => setTimeout(() => done('A'), 1000)) |
| 74 | + .job(done => setTimeout(() => done('B'), 500)) |
| 75 | + .job(done => setTimeout(() => done('C'), 300)) |
| 76 | + .done(results => { |
| 77 | + console.log(results); // ['A', 'B', 'C'] |
| 78 | + }); |
| 79 | +``` |
| 80 | + |
| 81 | +### fetchRetry |
| 82 | + |
| 83 | +Реализуйте функцию `fetchRetry`, которая выполняет HTTP-запрос по заданному URL с помощью `fetch` и автоматически повторяет попытку в случае ошибки. Функция должна принимать три аргумента: |
| 84 | + |
| 85 | +- `url` — строка с адресом запроса. |
| 86 | +- `retries` — максимальное количество попыток (включая первую). |
| 87 | +- `delay` — задержка (в миллисекундах) между повторными попытками. |
| 88 | + |
| 89 | +Если запрос завершается успешно, функция возвращает результат как обычный `fetch`. Если все попытки завершились неудачно, функция должна вернуть ошибку. |
| 90 | + |
| 91 | +```js |
| 92 | +fetchRetry('https://dummyjson.com/products', 3, 1000) |
| 93 | + .then(response => response.json()) |
| 94 | + .then(data => console.log(data)) |
| 95 | + .catch(error => console.error('Ошибка после всех попыток:', error)); |
| 96 | +``` |
| 97 | + |
| 98 | +**Требования:** |
| 99 | + |
| 100 | +- Если запрос завершился с ошибкой (например, сеть недоступна или получен некорректный HTTP-статус), функция должна подождать указанную задержку и попробовать снова, пока не исчерпает все попытки. |
| 101 | +- После успешного ответа функция должна вернуть результат без дополнительных попыток. |
| 102 | +- Если все попытки неудачны, функция должна вернуть ошибку. |
| 103 | + |
| 104 | + |
| 105 | +### debounce |
| 106 | + |
| 107 | +Напишите функцию `debounce`, которая принимает два аргумента: |
| 108 | +- функцию, которую нужно вызывать (например, обработчик событий) |
| 109 | +- время задержки в миллисекундах |
| 110 | + |
| 111 | +Функция `debounce` должна возвращать новую функцию-обёртку. Эта обёртка при каждом вызове не будет сразу запускать исходную функцию, а будет откладывать её выполнение на заданное количество миллисекунд. Если обёртку вызвать ещё раз до истечения задержки, предыдущий таймер отменяется и запускается новый отсчёт. В итоге исходная функция будет вызвана только один раз — спустя указанное время после последнего вызова обёртки |
| 112 | + |
| 113 | +```js |
| 114 | +function onInput(event) { |
| 115 | + console.log('Запрос к серверу:', event.target.value); |
| 116 | +} |
| 117 | + |
| 118 | +const debouncedOnInput = debounce(onInput, 500); |
| 119 | + |
| 120 | +inputElement.addEventListener('input', debouncedOnInput); |
| 121 | +``` |
| 122 | + |
| 123 | +В этом примере функция `onInput` будет вызываться только через 500 мс после того, как пользователь прекратил вводить текст, а не на каждое нажатие клавиши. |
| 124 | + |
| 125 | +**Что проверить:** |
| 126 | + |
| 127 | +- Исходная функция вызывается не чаще одного раза за указанный интервал времени. |
| 128 | + |
| 129 | +- При частых вызовах обёртки исходная функция не запускается, пока не наступит "пауза". |
| 130 | + |
| 131 | +- Аргументы и контекст (`this`) корректно передаются в исходную функцию. |
| 132 | + |
| 133 | +### serialProcess |
| 134 | + |
| 135 | +Напишите функцию `serialProcess`, которая принимает массив элементов и функцию-обработчик для каждого элемента. Обработчик должен вызываться для каждого элемента массива по очереди (строго по одному, не параллельно), и переходить к следующему элементу только после завершения обработки предыдущего. |
| 136 | + |
| 137 | +Функция-обработчик вызывается с четырьмя аргументами: |
| 138 | + |
| 139 | +- `el` — текущий элемент массива, |
| 140 | + |
| 141 | +- `index` — индекс текущего элемента, |
| 142 | + |
| 143 | +- `list` — исходный массив, |
| 144 | + |
| 145 | +- `done` — функция, которую нужно вызвать по завершении обработки элемента, передав ей результат обработки. |
| 146 | + |
| 147 | + |
| 148 | +Функция `serialProcess` должна возвращать промис, который резолвится после завершения обработки всех элементов, с массивом результатов в том же порядке, что и исходный массив. |
| 149 | + |
| 150 | +```js |
| 151 | +serialProcess([1,2,3,4,5], (el, index, list, done) => { |
| 152 | + console.log(`${el} start`); |
| 153 | + setTimeout(() => { |
| 154 | + console.log(`${el} end`); |
| 155 | + done(el * el); |
| 156 | + }, el * 100); |
| 157 | +}).then((list) => console.log(list)); // [1, 4, 9, 16, 25] |
| 158 | +``` |
| 159 | + |
| 160 | +**Требования:** |
| 161 | + |
| 162 | +- Каждый элемент обрабатывается только после завершения предыдущего. |
| 163 | + |
| 164 | +- Обработчик может быть асинхронным (например, содержать `setTimeout`). |
| 165 | + |
| 166 | +- Результаты собираются в массив в том же порядке, что и исходные элементы. |
| 167 | + |
| 168 | +- После обработки всех элементов промис резолвится с массивом результатов. |
| 169 | + |
| 170 | + |
| 171 | + |
10 | 172 | ## Критерии
|
11 | 173 |
|
12 | 174 | Домашнее задание ""Принято"" при наборе 3 и более баллов, иначе ""На доработку"".
|
|
0 commit comments