Reputation: 25986
I am doing some exercises on async/await
and I am completely blank on this one:
The
opA
function must be called before opB
, and opB
must be called beforeopC
. Call functions such a way thatC
thenB
thenA
is printed out.
const print = (err, contents) => {
if (err) console.error(err)
else console.log(contents )
}
const opA = (cb) => {
setTimeout(() => {
cb(null, 'A')
}, 500)
}
const opB = (cb) => {
setTimeout(() => {
cb(null, 'B')
}, 250)
}
const opC = (cb) => {
setTimeout(() => {
cb(null, 'C')
}, 125)
}
My guess is there is a typo in the question, so I should just have the functions print out A B C
and not C B A
?
My attempt is this:
(async function () {
await print(opA());
await print(opB());
await print(opC());
}());
but I get
cb(null, 'C')
^
TypeError: cb is not a function
Question
I have literally no idea how to solve this one, and don't understand the usage of the print
function.
Any help on how to get me going will be much appreciated =)
Upvotes: 0
Views: 356
Reputation: 6581
This question is very simliar to a lab exercise that I have spent some time with. Below are three solutions.
Note, that in the lab, the promisfy
module is included in the prompt; however, the callback solution, the first solution, doesn't need promsify at all.
'use strict'
const { promisify } = require('util')
const print = (err, contents) => {
if (err) console.error(err)
else console.log(contents)
}
const opA = (cb) => {
setTimeout(() => {
cb(null, 'A')
}, 500)
}
const opB = (cb) => {
setTimeout(() => {
cb(null, 'B')
}, 250)
}
const opC = (cb) => {
setTimeout(() => {
cb(null, 'C')
}, 125)
}
The instructions say that "A then B then C [must be] printed out", specifically in that order. Of course, simply calling each function by passing it the print
callback, prints them in the exact wrong order (due to the cleverly crafted timeouts).
The first solution focuses on providing a callback other than the print()
callback function. It is easy to call opA(print)
, and that works...if you want these to run in parallel.
To run these in series, in a given order, synchronously, each will have to complete before the next. To accomplish this, craft a slightly more complex callback, like this:
opA((err, out) => {
// opA() completed...pass opA output to print()
print(err, out)
// now call opB() from within the opA() callback
opB((err, out) => {
// opB() completed...pass the opB output to print()
print(err, out)
// etc...
opC((err, out) => {
print(err, out)
})
})
})
The second and third solutions make use of the promisfy
module.
Solution 2 uses then
and catch
. For the purposes of simplifying the solution, we can omit catch()
(however, it is not recommended to omit the catch in a production application).
In my opinion, promisfying the functions to use then
/catch
overcomplicates the otherwise simple callback solution (solution 1). Invariably, both solution 1 and solution 2 are their own private, callback hell.
const a = promisify(opA);
const b = promisify(opB);
const c = promisify(opC);
a()
.then((out)=> {
// just like the callback solution
// we wait in this `then` to call `print`
print(null, out)
// and just like in the callback solution
// now we nest another layer of callback hell
b()
.then((out)=> {
print(null, out)
// etc...
c()
.then((out)=> {
print(null, out)
})
})
})
Solution 3 is the most modern and flexible. It implements async
and await
.
Note: the two variables returned by opA(), opB(), and opC() are destructured into the variables err
and out
by these statements: [err, out] = await a()
.
const a = promisify(opA);
const b = promisify(opB);
const c = promisify(opC);
const main = async () => {
let [err, out] = await a();
print(err, out);
[err, out] = await b();
print(err, out);
[err, out] = await c();
print(err, out);
}
main();
Upvotes: 0
Reputation: 14423
The order in which you call these functions is almost irrelevant for the desired result. The timers are set to run in that specific order, first C
, then B
then A
.
So you can just call them:
opA(print);
opB(print);
opC(print);
Or even:
opB(print);
opA(print);
opC(print);
Or even:
opC(print);
opB(print);
opA(print);
However, there are ways in which you can switch the order in which would give you a wrong result. For example:
opA((err, a) => (
print(err, a),
opB((err,b) => (
print(err, b),
opC(print)
))
))
Which will call opB
after the timer set by opA
is ran and opC
is also called after opB
timer is ran.
I believe the purpose of the exercise might be so you can observe that the order in which you call your functions doesn't always reflect the order you might intuitively expect.
Upvotes: 2
Reputation: 136104
You said this is an async/await exercise but the code you show is the complete antithesis of async/await - it uses the callback paradigm.
To make your code print C B A
you would need to pass callbacks to the opX
functions in such an order to make them print their results:
const print = (err, contents) => {
if (err) console.error(err)
else console.log(contents )
}
const opA = (cb) => {
setTimeout(() => {
cb(null, 'A')
}, 500)
}
const opB = (cb) => {
setTimeout(() => {
cb(null, 'B')
}, 250)
}
const opC = (cb) => {
setTimeout(() => {
cb(null, 'C')
}, 125)
}
opA(print);
opB(print);
opC(print);
Upvotes: 4
Reputation: 40842
The function stored in optA
, opB
, opC
accept a callback function cb
that is called in the timeout, with the first argument set to null
and the second to A
, B
, C
.
print
holds a function that accepts an error (err
) as first argument and the thing to print as the second argument (contents
).
So you would combine the opt
function with print
that way: optA(print)
.
In the current form of the question, it would just be:
opA(print)
opB(print)
opC(print)
const print = (err, contents) => {
if (err) console.error(err)
else console.log(contents )
}
const opA = (cb) => {
setTimeout(() => {
cb(null, 'A')
}, 500)
}
const opB = (cb) => {
setTimeout(() => {
cb(null, 'B')
}, 250)
}
const opC = (cb) => {
setTimeout(() => {
cb(null, 'C')
}, 125)
}
opA(print)
opB(print)
opC(print)
To get the result: C
, B
, A
(due to the delays used for the setTimeouts
).
But there might be something missing in the question.
Upvotes: 2