0

I have below code consisting of three functions and a call back function. The challenge I am facing here is : I have to print A , then B and then C in this sequence only

I have tried below code but it always prints C , B and then A

I understand that this is happening due to the fact that setTimeout A > setTimeout B > setTimeout C.

But is there any way that I can call B only when A's response is obtained and C is called only when B's response is obtained.

Please help as I am stuck here

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)
}

Code I tried :

function promisifyA(){
    return new Promise( (resolve,reject) => {
      resolve(opA(print));
    });
}

function promisifyB(){
  return new Promise( (resolve,reject) => {
    resolve(opB(print));
  });
}


function promisifyC(){
  return new Promise( (resolve,reject) => {
    resolve(opC(print));
  });
}


promisifyA().then(() => {
  return promisifyB();
}).then(() => {
  return promisifyC();
});
Atul
  • 1,560
  • 5
  • 30
  • 75
  • This should help: [How to make a promise from setTimeout](https://stackoverflow.com/q/22707475/218196) – Felix Kling Apr 03 '21 at 11:14
  • In the first code block, you define functions, but never call them. Can you add how you started the call-chain and got the output? – trincot Apr 03 '21 at 11:21
  • That should be `return new Promise( (resolve,reject) => { opA(resolve); });` - otherwise you only have `print` as the callback but still call `resolve` immediately. Then use `promisifiedA().then(print).then(promisifiedB).then(print).…`. – Bergi Apr 03 '21 at 12:17

2 Answers2

1

In the first (non-promise) approach I suppose you are calling your functions like this:

opA(print);
opB(print);
opC(print);

And clearly, all three functions opA, opB and opC are called immediately one after the other. Here is how to call them as part of the callback that you pass:

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((err, contents) => {
    print(err, contents);
    opB((err, contents) => {
        print(err, contents);
        opC(print);
    });
});

Although this will achieve what you want, this also leads to what is called "callback hell". If you repeat this pattern, the indentation just keeps increasing...

So that is where promises can help out. First promisify setTimeout:

const delay = (ms, value) => new Promise(resolve => 
    setTimeout(() => resolve(value), ms)
);

const output = console.log;
const error = console.error;
const opA = () => delay(500, 'A');
const opB = () => delay(250, 'B');
const opC = () => delay(125, 'C');

opA().then(output)
     .then(opB)
     .then(output)
     .then(opC)
     .then(output)
     .catch(error);
trincot
  • 317,000
  • 35
  • 244
  • 286
0

You should only resolve() when the function is done. I.e

function promisifyA(){
    return new Promise( (resolve,reject) => {
      opA((err, val) => { 
            print(val); 
            resolve()
        });
    });
}
Rani Sharim
  • 610
  • 3
  • 7
  • You shouldn't `print` in an asynchronous callback though. Put it into a `then` promise callback. – Bergi Apr 03 '21 at 12:17