0

I have come across similar questions, but none that quite fits my scenario.

In the code below, I am using the listContainers() function from the dockerode Javascript library, to list the ids of my Docker containers. The snippet is adapted from one on the dockerode README. The listContainers call works and the console.log line outputs the ids as expected. The problem is that I cannot push the container IDs into the array declared outside the function call - the result is that the array is still empty after the listContainers call.

I am not very experienced with Javascript, but I think this problem is due to attempting the push inside the callback function. The problem is that the listContainers is asynchronous, so this means that //CONSOLE LOG #2 actually executes before //CONSOLE LOG #1.

How can I capture the id values into the ids array outside the function call?

//Here is where I want to store my container ids.
var ids = [];

//Here is the dockerode call
dockerCli.listContainers(function(err, containers) {

    containers.forEach(function(containerInfo) {

        //log shows the correct id
        console.log(containerInfo.Id);

        //Here I try to save the container id to my array
        ids.push(containerInfo.Id);
    });

    //CONSOLE LOG #1 Here I can see that the array has the correct values
    console.log("IDs: "+ids.toString());
});

//CONSOLE LOG #2 Shows that the array is empty
console.log("IDs: "+ids.toString());
3
  • 1
    Does listContainers result in an asynchronous callback? Commented Nov 19, 2015 at 16:17
  • Hmm, it makes an external call to a Docker server, so yes I think so. Do I need to use a Javascript promise? Commented Nov 19, 2015 at 16:19
  • 1
    That may be one way to work with it, yes. See this question - the way the question is phrased is slightly different (in that it's trying to return from a function rather than an inline callback) but the premise is the same. Commented Nov 19, 2015 at 16:20

2 Answers 2

1

With the help of other commenters, I realised that the listContainers call is asynchronous and there is simply no way to return a value from it.

So how to initialise and work with my ids array? I created my own function that wraps the dockerode listContainers call. This function then takes its own callback to do the work with the ids array. This allowed me to access the initialised ids array in my own callback, separating the functionality of processing the ids array from fetching the container list.

ids = [];

//Define my function that takes a callback function
//and just fetch the container ids
function getContainerJsonFromDocker(callback) {

    dockerCli.listContainers(function(err, containers) {

        containers.forEach(function(containerInfo) {
            console.log(containerInfo.Id);
            ids.push(containerInfo.Id);
        });
        return callback(ids);
    });
}

//Now call my function, and pass it an anonymous callback
//The callback does the processing of the ids array
getContainerJsonFromDocker(function(ids) {

    //This shows the array is initialised :)
    console.log("IDs: " + ids.toString());

    //Write my array to .json file
    var outputFilename = 'data.json';
    fs.writeFile(outputFilename, JSON.stringify(ids, null, 4),
            function(err) {
                if (err) {
                    console.log(err);
                } else {
                    console.log("JSON saved to " + outputFilename);
                }
            });
});
Sign up to request clarification or add additional context in comments.

Comments

0

you dont need to pass the global variable ids along with callback try this,

//Here is where I want to store my container ids.
var ids = [];

//Here is the dockerode call
dockerCli.listContainers(function(err, containers) {

    containers.forEach(function(containerInfo) {

        //log shows the correct id
        console.log(containerInfo.Id);

        //Here I try to save the container id to my array
        ids.push(containerInfo.Id);
    });
});

//Shows that the array is empty
console.log("IDs: "+ids.toString());

11 Comments

The result is still the same if I do not pass the variable. The problem is something else, to do with scope inside the callbacks
have you tried your console out put inside the listContainers callback function?
Yes, console.log("IDs: "+ids.toString()); works if I place it outside the forEach, but inside the listContainers function. The problem is that the listContainersis asynchronous, so this does not get called until after my other code has executed. I will update my question.
Its clear, that ids only filled up when this callback is executed
@KLibby - What kind of suggestion are you looking for? You cannot output data that has not arrived yet. Have you read the question at the link provided by @JamesThorpe?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.