Ошибка при передачи аргументов в callback
Я имею некий опыт написания js кода, но все же, я всегда имею проблемы при передачи аргументов в асинхронную функцию, и часто так бывает, что переданные мною аргументы уже не существуют и/или имеют значение undefined, и тут появляются различные проблемы. Так же, частой проблемой, после выполненной работы асинхронной функции, я не могу сохранить результат в переменные, которые были декларированы до использования асинхронной функции. Я знаю, что происходит в таких ситуациях, но как мне решить эту проблему и сохранять результаты в вышедекларированные переменные, я не знаю.
Пример такой вот проблемы:
Предположим, что у меня есть массив с определенной информацией для подключения к удаленному хосту:
// Hosts output
var Hosts = [{
hostName : 'test1',
password : 'pass1',
ipAddress : '192.168.0.1',
}, {
hostName : 'test2',
password : 'pass2',
ipAddress : '192.168.0.2',
}, {
hostName : 'test3',
password : 'pass3',
ipAddress : '192.168.0.3',
}];
в моем случаи, их 3.
Для того, чтобы подключиться к удаленному хосту, я использую simple-ssh модуль. Прежде чем подключиться к хосту, нужно создать сессию для каждого хоста. Делаю я это таким вот образом:
...
var SshSessions = [];
var index = 0, len = 0;
for (index = 0, len = Hosts.length; index < len; ++index) {
var sshSession = new ssh({
user : Hosts[index].hostName,
pass : Hosts[index].password,
host : Hosts[index].ipAddress,
timeout : 3000
});
SshSessions.push(sshSession);
}
index = 0;
len = 0;
for (index = 0, len = SshSessions.length; index < len; ++index) {
SshSessions[index].exec('Любая команда', {
out : function (stdout) {},
err : function (stderr) {},
exit: function (code) {}
}).start();
}
И тут у меня появляются проблемы. Моя задача, это выполнить определенную команду на удаленном хосте благодаря ssh сессии, и сохранить полученный результат в MySql. Так как SshSession работает асинхронно, я вызываю сохранения полученного результата в out:
for (index = 0, len = SshSessions.length; index < len; ++index) {
SshSessions[index].exec('Любая команда', {
out : function (stdout) {
connection.query('Любая заявка SQL'), function(err, result) {
...
})
},
err : function (stderr) {},
exit: function (code) {}
}).start();
}
В самой заявке, я должен подать ipAddress хоста. Но при подаче его таким вот образом:
out: function (stdout) {
connection.query('call updateHost(' + SshSessions[index].host + ', ' + stdout + ')'), function(err, result) {
//console.log(stdout);
if (err) {
console.log(err);
}
});
},
у меня выходит ошибка, так как - SshSessions[index].host = undefined.
Каким образом нужно передавать аргументы, да и вообще работать с асинхронными методами, чтобы не было таких вот проблем. В моем случаи, я сначала создаю ssh сессию, после чего получаю результат от отправленной команды, и лишь после получения результата, отправляю этот результат по данному хосту в MySQL базу данных.
PS. Буду очень благодарен, если предоставите пример создания правильной структуры работы с асинхронными методами. В интернете смотрел многие примеры - но они мне ясности не дали.
Ответы (1 шт):
Для работы с асинхронными функциями/кодом можно использовать Promise API/(Async/Await).
Хорошие примеры есть здесь
Попробуйте так:
(async() => {
var SshSessions = [];
var index = 0, len = 0;
for (index = 0, len = Hosts.length; index < len; ++index) {
var sshSession = new ssh({
user : Hosts[index].hostName,
pass : Hosts[index].password,
host : Hosts[index].ipAddress,
timeout : 3000
});
SshSessions.push(sshSession);
}
index = 0;
len = 0;
for (index = 0, len = SshSessions.length; index < len; ++index) {
await new Promise((resolve, reject) => {
SshSessions[index].exec('Любая команда', {
out: function (stdout) {
connection.query('call updateHost(' + SshSessions[index].host + ', ' + stdout + ')'), function(err, result) {
//console.log(stdout);
if (err) {
console.log(err);
}
resolve();
});
},
err : function (stderr) {},
exit: function (code) {}
}).start();
});
}
})();
Ключевое слово await приостановит цикл пока функция внутри promise не вызовет resolve(). И в таком случае SshSessions[index].exec() будут выполнятся по очереди.