2015-11-19 2 views
0

Я столкнулся с подобными вопросами, но ни один из них не подходит для моего сценария.Изменение внешней переменной массива изнутри для каждого обратного вызова

В приведенном ниже коде я использую функцию listContainers() из библиотеки Javascript dockerode, чтобы перечислить идентификаторы моих контейнеров Docker. Этот фрагмент адаптирован из одного на докероде README. Выполняется вызов listContainers, а строка console.log выводит идентификаторы, как ожидалось. Проблема в том, что я не могу выталкивать идентификаторы контейнера в массив, объявленный вне вызова функции, - результат состоит в том, что после вызова listContainers массив остается пустым.

Я не очень разбираюсь в Javascript, но я думаю, что эта проблема связана с попыткой нажатия внутри функции обратного вызова. Проблема в том, что listContainers является асинхронным, поэтому это означает, что //CONSOLE LOG #2 фактически выполняет до //CONSOLE LOG #1.

Как я могу записать значения id в массив ids вне вызова функции?

//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()); 
+1

Получает ли 'listContains' асинхронный обратный вызов? –

+0

Хм, он делает внешний звонок на сервер Docker, так что да, я так думаю. Нужно ли использовать Javascript-обещание? – EkcenierK

+1

Это может быть один из способов работать с ним, да. См. [Этот вопрос] (http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) - способ формулировки вопроса немного отличается (тем, что он пытаясь вернуться из функции, а не встроенного обратного вызова), но предпосылка такая же. –

ответ

1

С помощью других комментаторов, я понял, что listContainers вызова асинхронный и там просто нет пути чтобы вернуть значение из него.

Итак, как инициализировать и работать с моим массивом ids? Я создал свою собственную функцию, которая завершает вызов dockerode listContainers. Затем эта функция выполняет собственный обратный вызов для работы с массивом ids. Это позволило мне получить доступ к инициализированному массиву идентификаторов в моем обратном вызове, отделив функциональность обработки массива ids от выбора списка контейнеров.

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

вам не нужно передавать глобальные переменные идентификаторы вместе с обратным вызовом попробовать это,

//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()); 
+0

Результат все тот же, если я не передаю переменную. Проблема - это что-то еще, что касается области внутри обратных вызовов – EkcenierK

+0

, вы пробовали использовать консоль внутри функции callback-функции listContainers? – azad

+0

Да, 'console.log (« IDs: »+ ids.toString());' работает, если я помещаю его вне 'forEach', но внутри функции' listContainers'. Проблема в том, что 'listContainers' является асинхронным, поэтому он не вызывается до тех пор, пока не будет выполнен другой код. Я уточню свой вопрос. – EkcenierK

Смежные вопросы