-
-
Save monochromer/812cc71b319b1ae64c1c8e325bd5ad88 to your computer and use it in GitHub Desktop.
| /* | |
| conf: Falsy Values 2015 | |
| author: Kornel Lesinski | |
| theme: And .then() what? Promise programming patterns | |
| link: https://www.youtube.com/watch?v=KrhQE8K2I7Q | |
| */ | |
| // 1 waterfall. Использование результатов предыдущих промисов | |
| doFirst() | |
| .then(firstResult => { | |
| return doSecond() | |
| .then(seondResult => { | |
| return doThird() | |
| .then(thirdResult => f(firstResult, seondResult, thirdResult)) | |
| }) | |
| }) | |
| // 2 cache. Кеширование результатов асинхронных действий | |
| const cache = new Map(); | |
| function work(input) { | |
| if (!cache.has(input)) { | |
| const promise = asyncWork(input); | |
| cache.set(input, promise); | |
| }; | |
| return cache.get(input); | |
| } | |
| // 3. serial queue. Последовательное выполнение промисов друг за другом | |
| function serial(fnArray, onError, initialData) { | |
| return fnArray | |
| .reduce((p, f) => p.then(f), Promise.resolve(initialData)) | |
| .catch(onError); | |
| } | |
| // 4. Часто запрашиваемые данные одного и того же ресурса | |
| let currentPromise = null; | |
| function currentWeather() { | |
| if (!currentPromise) { | |
| currentPromise = fetch('/url.json') | |
| .then(res => res.json()) | |
| .catch(err => console.log(err)) | |
| .then(() => currentPromise = null); // finally | |
| }; | |
| return currentPromise; | |
| } | |
| // пример общей функции | |
| function createBalanceLoadFunction(fn, onError) { | |
| let currentPromise = null; | |
| return function(...args) { | |
| if (!currentPromise) { | |
| currentPromise = fn(...args) // check if fn returns not promise | |
| .catch(onError ? onError : console.error) | |
| .finally(() => currentPromise = null); | |
| }; | |
| return currentPromise; | |
| } | |
| } | |
| // 5. ready event. Работа с событиями | |
| let DOM = { | |
| ready: new Promise(resolve => { | |
| document.addEventListener('DOMContentLoaded', function onDOMContentLoaded() { | |
| document.removeEventListener('DOMContentLoaded', onDOMContentLoaded); | |
| resolve(); | |
| }); | |
| }) | |
| }; | |
| DOM.ready.then(doYourWork); | |
| // example === | |
| /* | |
| fetch(URL) | |
| .then(res => res.json()) | |
| .then(data => Object.keys(data).map(key => data[key])) | |
| .then(result => console.log(result)) | |
| .catch(error => console.error(`${error.message}, \n, ${error.stack}`)) | |
| */ | |
| serial([ | |
| (url) => fetch(url), | |
| res => res.json(), | |
| data => Object.keys(data).map(key => data[key]), | |
| result => console.log(result) | |
| ], | |
| error => console.error(`${error.message}, \n, ${error.stack}`), | |
| URL | |
| ) | |
| // https://uxdesign.cc/crafting-beautiful-ux-with-api-requests-56e7dcc2f58e | |
| // timeout | |
| class TimeoutError extends Error {} | |
| function promiseWithTimeout(p, timeout = 5000) { | |
| return Primise.race([ | |
| p, | |
| new Promise((resolve, reject) => { | |
| setTimeout(reject, timeout, new TimeoutError(`It's timeout`)) | |
| }) | |
| ]) | |
| } | |
| // Minimum wait time | |
| // it protects your app from fast API responses. A min wait is a great pattern to use if you want to show a loading state to the user, but the API might respond quickly. Users will end up seeing loading states and data “pop” into view before they can focus on anything. | |
| // retry | |
| // Отменяемые промисы | |
| // https://noteskeeper.ru/1385/ | |
| // https://blog.bloomca.me/2017/12/04/how-to-cancel-your-promise.html | |
| // Promise.allSettled | |
| // https://github.com/jasonwilliams/proposal-promise-allSettled | |
| // Promise.any | |
| // Promise.some | |
| /* | |
| Promise.allSettled — это такой аналог Promise.all, который не реджектится если один из промисов зареджектился. | |
| Я хотел бы предложить добавить еще два метода для работы с промисами — Promise.any и Promise.some. | |
| Типичный юзкейс Promise.any — у нас есть несколько разных URL и мы хотим получить ответ от быстрейшего. | |
| Может показаться, что для такой задачи подойдет Promise.race, но это не так. | |
| Promise.race возвращает любой fulfilled промис, будь он resolved или reject. | |
| Мы же хотим вернуть именно успешный, разрезолвленный промис и реджектнуть только если все промисы реджектнулись. | |
| Promise.some принимает iterable первым параметром и число вторым. | |
| Он возвращает массив разрезолвленных промисов указанной во втором параметре длины. | |
| Если зареджектилось слишком много промисов (количество оставшихся промисов меньше, чем количество требуемых), | |
| то Promise.some сразу же реджектится. | |
| */ | |
| function any(promises) { | |
| return Promise.all( | |
| promises.map(promise => | |
| promise.then(val => { throw val; }, _ => _), | |
| ), | |
| ).then(() => { throw Error('no successful connections'); }, _ => _); | |
| } | |
| // или (https://dev.to/vitalets/what-s-wrong-with-promise-allsettled-and-promise-any-5e6o) | |
| const reverse = p => new Promise((resolve, reject) => Promise.resolve(p).then(reject, resolve)); | |
| Promise.any = arr => reverse(Promise.all(arr.map(reverse))); | |
| // композиция асинхронных функций | |
| // https://github.com/HowProgrammingWorks/AsyncCompose | |
| // | |
| function microtaskDebounce(fn) { | |
| let called = false | |
| return () => { | |
| if (called) { | |
| return | |
| } | |
| called = true | |
| window.Promise.resolve().then(() => { | |
| called = false | |
| fn() | |
| }) | |
| } | |
| } |
24 строка, что за функция
asyncWork?
Любая ваша функция, возвращающая результат асинхронной операции как promise
promiseWithTimeout - тут ошибка, race не для этого. тут должкен быть all и 2 резолва
тут ошибка, race не для этого
в чём ошибка?
тут ошибка, race не для этого
в чём ошибка?
В том что запустите ваш код и увидите что никакого таймаута нет. Race выдает первый выполненный промис.
Race выдает первый выполненный промис.
Race выдает promise, который первый поменял свое состояние. Если 2-ой промис завершится раньше, то мы должны поймать ошибку типа TimeoutError и отменить текущую операцию.
promiseWithTimeout(someAsyncOperation(), timeoutTime = 100)
.then((result) => console.log(result))
.catch((error) => {
if (error instanceof TimeoutError) {
console.log('need abort here async opertation')
return
}
throw error
})Race выдает promise, который первый поменял свое состояние
Мы с вами видимо про разные таймауты говорим. Вы сами привели ссылку над функцией в которой реализован таймаут. Так вот там таймаут именно в понимании обязательной задержки выполнения, а у вас таймаут про который вы щас пишите - отмена по истечению времени. При этом вы вырвали описание таймаута которое под фукцией с того сайта и оно неправильное в случае того что вы мне сейчас описываете! Перечитайте все сами!
там таймаут именно в понимании обязательной задержки выполнения
Там это pattern2 (Minimum wait time).
У меня в конспекте pattern1 (Timeouts). Вот он из статьи:
О терминологии. Минимальное ожидание - это скорее delay. Время, после которого операция должна оборваться - timeout. Именно так называется параметр в XMLHttpRequest.
Минимальное ожидание - это скорее delay
Я согласен с тем что это скорее delay. Но у вас либо тут отсутсвует часть записи, либо просто нкпонятно к чему относится minimum wait time.

24 строка, что за функция
asyncWork?