Skip to content

Instantly share code, notes, and snippets.

@rumkin
Last active January 29, 2022 15:15
Show Gist options
  • Save rumkin/807cb9857ffa62ec38c4347be9382053 to your computer and use it in GitHub Desktop.
Save rumkin/807cb9857ffa62ec38c4347be9382053 to your computer and use it in GitHub Desktop.
// 1. Функции, которые выполняют деление в синхронном и асинхронном стиле
function divide(a, b) {
if (b < 0) {
throw new Error('Divisin by zero')
}
return a / b
}
// * setImmediate внутри функции имитирует асинхронный вызов. Он нужен
// для переноса вычислений в следующий цикл вычислений.
function divideWithCallback(a, b, callback) {
setImmediate(() => {
if (b === 0) {
callback(new Error('Divisin by zero'))
}
else {
callback(null, a / b)
}
})
}
function divideWithPromise(a, b) {
return new Promise((resolve, reject) => {
if (b === 0) {
reject(new Error('Division by zero'))
}
resolve(a / b)
})
}
async function divideAsync(a, b) {
if (b === 0) {
throw new Error('Division by zero')
}
return a / b
}
// § 1
//
// Пример программ с использованием приведенных выше функций.
// В данном случае, все асинхронные примеры аналогичны вызову синхорнному примеру (1.1)
// в части результата
// 1.1 Вызов синхронного кода:
try {
console.log(div(1, 5) + div(4, 2) + div(3, 0))
} catch (err) {
console.error(err)
}
// 1.2 Вызов аналогичного кода, но с использованием вложенных коллбеков:
// Каждый блок кода должен обработать ошибку, иначе вызывающий код
// не дождется ответа и программа может повсети себя неожиданно:
// * зависнуть в ожидании ответа
// * прекратить выполнение не дожидаясь результата
// * дождаться результата, но не обработать его
divWithCallback(1, 5, (err, result1) => {
if (err) {
console.error(err)
return
}
divWithCallback(4, 2, (err, result2) => {
if (err) {
console.error(err)
return
}
divWithCallback(3, 0, (err, result3) => {
if (err) {
console.error(err)
return
}
console.log(result1 + result2 + result3)
})
})
})
// 1.3 Результат вычислений получается через отложенный вызов, но обработка ошибки
// может быть отложена в последний вызов.
divideWithPromise(1, 5)
.then((result) => result + divideWithPromise(4, 2))
.then((result) => result + divideWithPromise(3, 0))
.then((result) => console.log(result), (error) => console.error(error))
// 1.4 Вызов и использование divideAsync подобно divideWithPromise.
// Так как асинхронные функции возвращают объект Promise.
divideAsync(1, 5)
.then((result) => result + divideWithPromise(4, 2))
.then((result) => result + divideWithPromise(3, 0))
.then((result) => console.log(result), (error) => console.error(error))
// § 2
//
// Примеры вызовов синхронного и асинхроннных методов из других модулей приложения,
// предположим у нас есть некий функция doMath, котоая использует приведенные выше функции.
// Для наглядности добавим несколько функций add, addWithCallback, addWithPromise, addAsync,
// поведение которых подобно поведению divide, divideWithCallback, divideWithPromise, divideAsync.
function add(a, b) {
return a + b
}
function addWithCallback(a, b, callback) {
setImmediate(() => {
callback(a + b)
})
}
function addWithPromise(a, b) {
return new Promise((resolve, reject) => {
resolve(a + b)
})
}
async function addAsync(a, b) {
return a + b
}
// 2.1 Синхронный вызов.
function doMath(a, b) {
return add(a, div(a/b))
}
// 2.2а Использование коллбеков, всегда* требует применения коллбеков внутри
// т.е. код на коллбеках порождает код на коллбеках.
// * – некоторые методы возвращают Promise, если в вызов не был передан коллбек.
function doMathWithCallback(a, b, callback) {
divideWithCallback(a, b, (err, result) => {
if (err) {
callback(err)
return
}
addWithCallback(a, result, callbcack)
})
}
// 2.2б Код аналогичен предыдущему, но результат вызова в конце представлен в виде
// еще одного коллбека для наглядности. Смысл в том, что коллбек – это по сути "фрактальный"
// паттерн и каждый вложенный коллбек должен быть идентичен самому верхнему в цепочке,
// на практике это не всегда так и могут встречаться коллбеки с переменным числом аргументов
// что делает их вложенное использование затруднительным и требует дополнительной обработки.
function doMathWithCallback(a, b, callback) {
divideWithCallback(a, b, (err, result) => {
if (err) {
callback(err)
return
}
addWithCallback(a, result, (err, result) => {
if (err) {
callback(err)
return
}
callback(null, result)
})
})
}
// 2.3 Вызов методов обернутых в Promise, не требует дополнительного
// внешнего оборачивания.
function doMathWithPromise(a, b) {
return divideWithPromise(a, b)
.then((result) => addWithPromise(a, result))
}
// 2.4а doMathWithAsync позволяет сделать код более линейным
async function doMathWithAsync(a, b) {
const result = await divideAsync(a, b)
return addAsync(a, result)
}
// 2.4б Данный пример аналогичен
async function doMathWithAsync(a, b) {
return addAsync(a, await divideAsync(a, b))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment