0

I am wondering if it's possible to assign the value of callback to a variable. I recently ran into a problem with MongoClient's connect method, where I want to get the db object and pass it on to my class methods. Is there a way I can I assign hello world to var b.

function testCB(cb){
  setTimeout(() => {
    cb('Hello World')
  }, 1000)
}

let b = testCB('a', (str) => {
  return str;
})

console.log(b) //undefined
Yasin Yaqoobi
  • 1,888
  • 3
  • 27
  • 38
  • using asynchronous methods (setTimeout is asynchronous) means you have to write your code to handle asynchronicity ... nothing can change asynchronous code to synchronous - and as an aside, `testCB` function doesn't even have a return statement, so it could never return anything anyway – Jaromanda X Jul 04 '17 at 02:49
  • 2
    You can put `b = str;` inside the callback, but `console.log(b)` would still show `undefined` because it runs before the callback runs. Think about this: If you could somehow magically assign the value from the callback to `b` *synchronously*, why would you need a callback in the first place? – Felix Kling Jul 04 '17 at 02:55

2 Answers2

0

As the event is async, you need to follow the async code flow. So The only way to "get the return" is inside your callback function, i.e.:

function testCB(cb){
  setTimeout(() => {
    cb('Hello World')
  }, 1000)
}

let b = testCB('a', (str) => {
  // this executes async, when testCB finishes running
  console.log(str) // will print STR
  return str;
})
// this code executes BEFORE testCB finish running,
// so it is imposible to get the value of str here.

If you want a more fluid code, you can try using promises with async and await which are available on node 7+

Ninten
  • 565
  • 3
  • 10
0

Currently, you are assigning to b the result of invoking testCB, but testCB doesn't return anything, so nothing is assigned to b.

But there's nothing wrong with this pattern:

var b;

testCB( (str) => { b = str; } );

This is the simplest version of maintaining application state in a variable (b), and modifying that state with asynchronous functions.

If many parts of your application depend on b and you want to define that dependence synchronously: that's what Promises are for!

In that case, you could define:

var b = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Hello World'), 1000);
});

b.then((str) => {...do something with str...}
b.then((str) => {...do something else with str...}
doSomeThingWithB(b);

Where doSomeThingWithB of course knows that b is a promise (or "thennable").

A. Vidor
  • 2,502
  • 1
  • 16
  • 24
  • "*there's nothing wrong with this pattern*" - of course there is: all the code using `b` doesn't know whether it has already been assigned a value or not. – Bergi Jul 04 '17 at 04:31
  • @Bergi But that is always the case when you modify a state variable asynchronously. The problem of "subscribing to changes" in `b` and handling an `undefined` state is a different concern, and not what OP asked. The question was how to "break out" of the callback scope. – A. Vidor Jul 04 '17 at 15:30
  • I'm pretty sure he meant to "break out of the callback scope" while still doing the same thing. One cannot put the `console.log` outside a callback, or at least a separate scope. – Bergi Jul 04 '17 at 15:36