So there are several things going on. Broadly speaking, you are misinterpreting the scope of where the reference to devices is valid. devices is only valid inside of the function that defines it as a variable function(devices) {...}
But, so that you can better understand:
Let’s pretend that particle.listDevices was a Promise function we ourselves defined:
class particle {
listDevices(tokenObject) {
return new Promise(
function (call_this_function_if_succeeded, call_this_function_if_failed) {
if (isValidToken(tokenObject) && have_list_to_return) {
var devicesList = [ device1, device2, device3 ];
call_this_function_if_succeeded(devicesList); // resolve
} else {
var error_context = new Error('Could not get the devices list');
call_this_function_if_failed(error_context); // reject
}
});
};
}
A Promise is in essence a function with two mandatory arguments, a function that should get called if the task succeeds, and a function that should get called if the task fails. Why is this? A Promise allows you to do things asynchronously. This way you don’t have to actually wait for the response, and can do other things. Instead of just waiting, you pre-define what you want your program to do after the Promise is done doing whatever it’s going to do.
The devicesPr object is a wrapper on that whole complex structure containing the function callback references. It’s not data itself, but rather a variable containing the details of what how your program expects to hear back from the Promise function.
To use the results of this we use the devicesPr.then(...) terminology. A Promise object has a built in function, then which does the following:
class Promise {
...
then(call_this_function_if_succeeded, call_this_function_if_failed) {
this.my_call_this_function_if_succeeded = call_this_function_if_succeeded;
this.my_call_this_function_if_failed = call_this_function_if_failed;
return;
}
}
So when you call devicesPr.then(functionA, functionB), you are assigning devicesPr.my_call_this_function_if_succeeded = functionA and devicesPr.my_call_this_function_if_failed = functionB.
In your case, for brevity’s sake, we define the functions inside of the function call for devicesPr.then. You could just as easily structure it this way:
var devicesPr = particle.listDevices({ auth: token });
function handleSuccessfulListDevicesCall(devices) {
if (device.id === "23423452342etc..") {
sqlStuffFunction(device.id);
}
}
function handleErrorsFromListDevicesCall(error) {
console.log('List devices call failed: ', err);
}
devicesPr.then(handleSuccessfulListDevicesCall, handleErrorsFromListDevicesCall);
The only place the devices object exists is within the internals of particle.listDevices, and inside of whatever function you define as handleSuccessfulListDevicesCall(devices) {...}
I don’t know any PowerShell, but my assumption is that all variables seem to be essentially global. In JavaScript, all variables are very strongly limited to the context where they are defined, and any children of that context.
So great, let’s just copy the devices list to a global variable:
// Please don't do this!!
var devicesPr = particle.listDevices({ auth: token });
var global_devices_list = [];
function handleSuccessfulListDevicesCall(devices) {
global_devices_list = devices;
}
function handleErrorsFromListDevicesCall(error) {
console.log('List devices call failed: ', err);
}
devicesPr.then(handleSuccessfulListDevicesCall, handleErrorsFromListDevicesCall);
global_devices_list.forEach(
function (device) { // this never gets called because array is empty!!!!
if (device.id === "23423452342etc..") {
sqlStuffFunction(device.id);
}
}
);
Because a Promise is merely a promise that something will happen in the future, the javascript just keeps marching through the rest of your code until it reaches the end, and then eventually the Promise returns and calls the things you have defined to handle it.
The code above will try to loop through an empty array of devices because the promise has not yet populated it. Thus you have to wait until the result of the Promise is ready for you.
The .then terminology is what “waits” for the result. It is also what allows you to handle errors if things don’t work properly.
Think of your JavaScript code like an outline of what you want to have happen. Not everything happens in the order that you put it on the page, you are simply defining the relationships between things and what happens in response to what. Asynchronous stuff is super confusing.
At the end of all of this, what you should do is either what I mentioned in my last comment, or something like this:
var devicesPr = particle.listDevices({ auth: token });
function handleSuccessfulListDevicesCall(devices) {
// does absolutely everything you need to do with
// the devices list inside of here. You can call
// other things but be sure to pass in devices as
// an argument
// like you mentioned you wanted to do:
if (device.id === "23423452342etc..") {
sqlStuffFunction(device.id);
}
// do all the rest of the stuff you need to do after
// the SQL stuff is done HERE not outside of the fn
doTheRestOfTheStuffFunction();
}
function handleErrorsFromListDevicesCall(error) {
console.log('List devices call failed: ', err);
}
devicesPr.then(handleSuccessfulListDevicesCall, handleErrorsFromListDevicesCall);
People do the inline functions because it’s a little easier to read the flow once you understand them. But if the scope is too confusing, try the above to simplify that a little bit, maybe. Hope this is helpful / didn’t confuse you more haha.