0

Problem

I'm trying to get the diskName value back from this.getDiskName('C:') and assign it to element['name']:

getDisksInfo () { 
  ...
  element['name'] = this.getDiskName('C:')
  ...
},

getDiskName (diskLetter) {
  if (process.platform == 'win32') {
    var exec = require('child_process').exec
    var cmd = `wmic logicaldisk where caption="${diskLetter}" get VolumeName`

    exec(cmd, (err, stdout, stderr) => {
      if (err) {
        console.log(err)
      }
      let diskName = stdout.split('\n')[1]
      return diskName
    })
  }
}

I tried doing this, but I keep getting different errors:

getDiskName (diskLetter, callback) {
    ...
    exec(cmd, (err, stdout, stderr) => {
      if callback(null, () => {
        let diskName = stdout.split('\n')[1]
        return diskName
      })
    ...
}

Question

Could someone please explain how to return the value properly?

Un1
  • 3,874
  • 12
  • 37
  • 79
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – CodeF0x May 29 '18 at 12:19
  • @CodeF0x I couldn't adapt other answers to this code. I always get an error saying callback is not defined. Could you please give me a hint? – Un1 May 29 '18 at 12:22
  • You can't return it. Instead of `return diskName`, you need to set the value right there. I'll create an answer with a more idiomatic way to do this. – Michael Chaney May 29 '18 at 12:23
  • well did you pass it a callback so it is defined? – epascarello May 29 '18 at 12:23
  • @epascarello yes, but I don't know how to do it properly, I edited the code, could you please take a look? – Un1 May 29 '18 at 12:27
  • Child process docs show how you can `promisify` the `exec()` method – charlietfl May 29 '18 at 12:30
  • Using asynchronous functions is a new way of thinking for many. Instead of returning a value and then just using it, you typically write a "callback" function that does what you want done with the value and then cause that function to be invoked with the value when the async function completes. In JS this often takes the form of a promise and the "then" function thereof. – John Hascall May 29 '18 at 12:33

2 Answers2

1

Your problem is that you are missing either a callback coming into getDiskName() or a Promise() coming out.

Since the Promise approach seems to be more popular nowadays, I'll go with that for this answer.

With a Promise approach, you need the function to return a Promise. In most cases, you just wrap all the code up in a Promise and return that:

getDiskName(diskLetter) {
    return new Promise((resolve, reject) => {
      // rest of your code in the function
    });
}

Then, instead of your return, you'll call resolve():

let diskName = stdout.split('\n')[1];
resolve(diskName)

And for your error, you'll call reject:

if (err) {
  reject(err);
}

Then, in the function that uses it, you'll have to wait for the then() in your function:

this.getDiskName('C:').then(diskName => console.log(diskName))

The callback method is similar, you just pass in the callback into getDiskName and call it when you're ready.

samanime
  • 25,408
  • 15
  • 90
  • 139
  • Thank you for the explanation, I think I understand it now. I also wanted to use a promise for this, but I couldn't understand how they work, now it's clearer to me – Un1 May 29 '18 at 12:47
1

This is a more idiomatic method to handle a case like this. We'll pass a function in to getDiskName which takes the disk name (which is the return value) as a parameter.

getDisksInfo () { 
  ...
  this.getDiskName('C:', function(diskName) {
    element['name'] = diskName;
  });
  // Note that code from here to the end doesn't have access
  // to element['name']
  ...
},

getDiskName (diskLetter, func) {
  if (process.platform == 'win32') {
    var exec = require('child_process').exec
    var cmd = `wmic logicaldisk where caption="${diskLetter}" get VolumeName`

    exec(cmd, (err, stdout, stderr) => {
      if (err) {
        console.log(err)
      }
      let diskName = stdout.split('\n')[1]
      func(diskName);
    })
  }
}

Now, this still might not work for you since perhaps you have code after the call which relies on knowing the diskName. In that case, you would probably roll that code into your anonymous function. Perhaps getDisksInfo takes a function as a parameter instead.

This is the general pattern, you have to determine how it best fits in your program.

Michael Chaney
  • 2,911
  • 19
  • 26