Ваши обратные вызовы никогда не передают аргументы, cb()
.В реальной программе вы, вероятно, захотите получить результат обратно.Обратный вызов предназначен для получения какого-то сообщения - то, что вы перезваниваете , чтобы сказать ?В этой программе мы отправим несколько сообщений и убедимся, что все они будут переданы в окончательный обратный вызов -
function first(cb) {
console.log('first()')
cb(1) // return some result
}
function second(cb) {
console.log('second()')
cb(2) // return some result
}
function third(cb) {
console.log('third()')
cb(3) // return some result
}
function last(cb) {
console.log('last()')
cb('last') // return some result
}
function runCallbacksInSequence(fns, cb) {
fns.reduce
( (r, f) => k => r(acc => f(x => k([ ...acc, x ])))
, k => k([])
)
(cb)
}
const fns =
[ first, second, third, last ]
runCallbacksInSequence(fns, results => {
console.log("-- DONE --")
console.log(...results)
})
Выход -
first()
second()
third()
last()
-- DONE --
1 2 3 'last'
Для дополнительной дозы функционального программирования -
Приведенный выше редуктор основанна фундаментальной структуре данных под названием Продолжение .Если мы извлечем его, мы увидим, что runCallbacksInSequence
делает более четко -
function append (a = [], x = null) {
return a.concat([ x ]) // basic append operation
}
function runCallbacksInSequence(fns, cb) {
Cont.run
( fns.reduce // in the context of Cont ...
( Cont.lift2(append) // reduce using append
, Cont.of([]) // init with empty array
)
, cb
)
}
Вот Cont
-
const Cont =
{ of: x =>
k => k (x)
, lift2: f => (mx, my) =>
k => mx (x => my (y => k (f (x, y))))
, run: (c, k) =>
c (k)
}
Разверните фрагмент ниже, чтобы увидеть результат в вашемсобственный браузер -
function first(cb) {
console.log('first()')
cb(1) // return some result
}
function second(cb) {
console.log('second()')
cb(2) // return some result
}
function third(cb) {
console.log('third()')
cb(3) // return some result
}
function last(cb) {
console.log('last()')
cb('last') // return some result
}
const Cont =
{ of: x =>
k => k (x)
, lift2: f => (mx, my) =>
k => mx (x => my (y => k (f (x, y))))
, run: (c, k) =>
c (k)
}
function append (a = [], x = null) {
return a.concat([ x ])
}
function runCallbacksInSequence(fns, cb) {
Cont.run
( fns.reduce
( Cont.lift2(append)
, Cont.of([])
)
, cb
)
}
const fns =
[ first, second, third, last ]
runCallbacksInSequence(fns, results => {
console.log("-- DONE --")
console.log(...results)
})
Использование reduce
- не единственный способ выразить такую программу.Программирование - все о изобретении Вашего собственного удобства.Что если бы у нас была интуитивная магическая функция, например $
ниже?Мы могли бы начать с некоторого значения, а затем просто связать столько необходимых шагов -
$ ([])
(andAppend(first))
(andAppend(second))
(andAppend(second))
(andAppend(third))
(andAppend(third))
(andAppend(third))
(andAppend(last))
(x => console.log ("done", x))
// first()
// second()
// second()
// third()
// third()
// third()
// last()
// "done" [ 1, 2, 2, 3, 3, 3, "last" ]
Любая простая функция может идти в последовательности -
function progress(p) {
console.log("progress:", p)
return p
}
$ ([])
(andAppend(first))
(andAppend(second))
(progress)
(andAppend(third))
(andAppend(last))
(x => console.log ("done", x))
// first()
// second()
// progress: [ 1, 2 ]
// third()
// last()
// "done" [ 1, 2, 3, "last" ]
Это кажется очень интуитивным способомработать с нашими асинхронными функциями.Нам просто нужно реализовать $
сейчас.Насколько сложно это может быть?
const $ = x =>
k => $(Promise.resolve(x).then(k))
А теперь мы реализуем andAppend
-
function andAppend(f) {
return acc =>
new Promise(r =>
f(x => r([ ...acc, x ]))
)
}
Разверните фрагмент ниже, чтобы увидеть, как работает ваш браузер -
function first(cb) {
console.log('first()')
cb(1)
}
function second(cb) {
console.log('second()')
cb(2)
}
function third(cb) {
console.log('third()')
cb(3)
}
function last(cb) {
console.log('last()')
cb('last')
}
function andAppend(f) {
return acc =>
new Promise(r =>
f(x => r([ ...acc, x ]))
)
}
function progress(p) {
console.log("progress:", p)
return p
}
const $ = x =>
k => $(Promise.resolve(x).then(k))
$ ([])
(andAppend(first))
(andAppend(second))
(progress)
(andAppend(third))
(andAppend(last))
(x => console.log ("done", x))