Last active
January 29, 2022 15:15
-
-
Save rumkin/807cb9857ffa62ec38c4347be9382053 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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