[英]NodeJS Convert Promises to Promise.all
I have a NodeJS script that I have been working on, but the biggest problem I have is that chaining all of these promises is not only ugly to look at, but difficult to maintain as time goes on. 我有一个正在工作的NodeJS脚本,但是最大的问题是,将所有这些诺言链接起来不仅看起来很丑,而且随着时间的推移很难维护。
I want to convert these individual promises into one, using the Promise.all()
method, but am not sure how I can get the same functionality and assign variables from one promise to another using this method. 我想使用
Promise.all()
方法将这些单独的承诺转换为一个,但是不确定如何使用该方法获得相同的功能并将变量从一个承诺分配给另一个承诺。
For example, my second promise: methods.login()
returns a sessionId that is used in almost every other promise. 例如,我的第二个Promise:
methods.login()
返回一个几乎在所有其他Promise中使用的sessionId。 How would I assign that variable and pass it to further dependent promises using Promise.all()
?? 我将如何使用
Promise.all()
分配该变量并将其传递给其他相关的Promise.all()
?
Here is my current code: 这是我当前的代码:
var zabbixApi = require('./zabbixapi.js');
var methods = require('./methods.js');
var fs = require('fs');
var SESSIONID;
function main() {
var apiVersion, loggedOut, numTemplates, numHosts, numHostGroups, numItems;
var templates = []
, hostGroups = []
, hosts = [];
/*var promises = [];
promises.push(zabbixApi(methods.getApiVersion()));
promises.push(zabbixApi(methods.login(SESSIONID)));
promises.push(zabbixApi(methods.getHostGroups(SESSIONID)));
promises.push(zabbixApi(methods.getTemplates(SESSIONID)));
promises.push(zabbixApi(methods.getHosts(SESSIONID)));
// promises.push(zabbixApi(methods.configExport(hostIds, templateIds, groupIds, SESSIONID)));
promises.push(zabbixApi(methods.logout(SESSIONID)));
Promise.all(promises).then(function (values) {
console.log('All promises completed.');
}, function (reason) {
console.log('Error completing promises: ' + reason);
});*/
// Get API version
zabbixApi(methods.getApiVersion())
// If successful, login to the API
.then(function (version) {
apiVersion = version.result;
// Verify that the API version returned is correct
if (apiVersion.length < 5 || !apiVersion) {
console.log('Error occurred retrieving API version: ' + version.error.data);
return 1;
} else {
return zabbixApi(methods.login(SESSIONID));
}
}, function (error) {
console.log('Error occurred retrieving API version: ' + error);
return 1;
// If login successful, continue operations until logged out or error
}).then(function (auth) {
SESSIONID = auth.result;
if (!SESSIONID) {
console.log('Error retrieving session id: ' + auth.error.data);
return 1;
} else {
console.log('Logged in successfully!');
return zabbixApi(methods.getHostGroups(SESSIONID));
}
}, function (error) {
console.log('Error occurred authenticating: ' + error);
return 1;
// Attempt to retrieve all hostgroup information
}).then(function (hostgroups) {
numHostGroups = hostgroups.result.length;
hostGroups = hostgroups.result;
if (!numHostGroups) {
console.log('Error occurred retrieving host groups: ' + hostgroups.error.data);
return 1;
} else {
return zabbixApi(methods.getTemplates(SESSIONID));
}
}, function (error) {
console.log('Error occurred retrieving host groups: ' + error);
return 1;
// Attempt to retrieve host information
}).then(function (template) {
numTemplates = template.result.length;
templates = template.result;
if (!numTemplates) {
console.log('Error occurred retrieving templates: ' + template.error.data);
return 1;
} else {
return zabbixApi(methods.getHosts(SESSIONID));
}
}, function (error) {
console.log('Error occurred retrieving templates: ' + error);
return 1;
// Attempt to retrieve host information
}).then(function (hosts) {
numHosts = hosts.result.length;
hosts = hosts.result;
if (!numHosts) {
console.log('Error occurred retrieving host groups: ' + hosts.error.data);
return 1;
} else {
var groupIds = []
, hostIds = []
, templateIds = [];
// Extract all groupIds for host groups
for (var i = 0; i < numHostGroups; i++) {
groupIds[i] = hostGroups[i].groupid;
}
// Extract all hostIds for hosts
for (var i = 0; i < numHosts; i++) {
hostIds[i] = hosts[i].hostid;
}
// Extract all templateIds for templates
for (var i = 0; i < numTemplates; i++) {
templateIds[i] = templates[i].templateid;
}
return zabbixApi(methods.configExport(hostIds, templateIds, groupIds, SESSIONID));
}
}, function (error) {
console.log('Error occurred retrieving host groups: ' + error);
return 1;
// Attempt to retrieve configuration information
}).then(function (config) {
//console.log(config);
if (config.error) {
console.log('Error occurred retrieving configuration: ' + config.error.message + ': ' + config.error.data);
return 1;
} else {
if (!writeToFile(config)) {
return 1;
} else {
console.log('Configuration details exported successfully.');
}
return zabbixApi(methods.logout(SESSIONID));
}
}, function (error) {
console.log('Error occurred retrieving configuration: ' + error);
return 1;
// Attempt to logout of API, if logout successful exit safely
}).then(function (logout) {
loggedOut = logout.result;
if (!loggedOut) {
console.log('Error logging out: ' + logout.error.data);
return 1;
} else {
console.log('Logged out successfully!');
return 0;
}
}, function (error) {
console.log('Error occurred logging out: ' + error);
return 1;
});
}
function writeToFile (config) {
fs.writeFile('zabbix_config_export.json', JSON.stringify(config), function (err) {
if (err) {
return console.log('Error writing configuration to file: ' + err);
}
});
return true;
}
main();
You can use Promise.all()
on operations that can run in parallel, but not on operations that must be performed in a specific sequence. 您可以对可以并行运行的操作使用
Promise.all()
,但不能对必须按特定顺序执行的操作使用。
In looking at your code, it appears that you do have a couple places where you can do some operations in parallel, but not all your operations can be done that way. 在查看代码时,似乎确实有几个地方可以并行执行一些操作,但并非所有操作都可以通过这种方式完成。 It appears you can do things in this general sequence:
看来您可以按照以下一般顺序进行操作:
getApiVersion
Login to session
In parallel (getHostGroups, getTemplates, getHosts)
configExport previous results
In parallel (logout, writeToFile)
That can be achieved like this: 可以这样实现:
var zabbixApi = require('./zabbixapi.js');
var methods = require('./methods.js');
var fs = require('fs');
var SESSIONID;
function logout() {
if (SESSIONID) {
var p = zabbixApi(methods.logout(SESSIONID));
// clear SESSIONID to show that we've already launched a logout attempt, no need to try again
SESSIONID = null;
return p;
} else {
return Promise.resolve();
}
}
function main() {
var apiVersion, hostGroups, templates, hosts;
// Get API version
zabbixApi(methods.getApiVersion())
// If successful, login to the API
.then(function (version) {
apiVersion = version.result;
// Verify that the API version returned is correct
if (!apiVersion || apiVersion.length < 5) {
throw new Error('Error occurred retrieving API version: ' + version.error.data);
} else {
return zabbixApi(methods.login(SESSIONID));
}
}, function (error) {
throw new Error('Error occurred retrieving API version: ' + error);
// If login successful, continue operations until logged out or error
}).then(function (auth) {
SESSIONID = auth.result;
if (!SESSIONID) {
throw new Error('Error retrieving session id: ' + auth.error.data);
} else {
console.log('Logged in successfully!');
// now that we are logged in, a number of operations can be launched in parallel
return Promise.all([
zabbixApi(methods.getHostGroups(SESSIONID),
zabbixApi(methods.getTemplates(SESSIONID),
zabbixApi(methods.getHosts(SESSIONID)
]);
}
}, function (error) {
throw new Error('Error occurred authenticating: ' + error);
// we have hostGroups, templates and hosts here
}).then(function(r) {
// r[0] = hostGroups, r[1] = templates, r[2] = hosts
// check hostGroups
hostGroups = r[0].result;
if (!hostGroups.length) {
throw new Error('Error occurred retrieving host groups: ' + hostgroups.error.data);
}
// check templates
templates = r[1].result;
if (!templates.length) {
throw new Error('Error occurred retrieving templates: ' + template.error.data);
}
// check host information
hosts = r[2].result;
if (!hosts.length) {
throw new Error('Error occurred retrieving host groups: ' + hosts.error.data);
}
// utility function for retrieving a specific property from each array of objects
function getIds(array, prop) {
return array.map(function(item) {
return item[prop];
});
}
var groupIds = getIds(hostGroups, "groupid");
var hostIds = getIds(hosts, "hostid");
var templateIds = getIds(templates, "templateid");
return zabbixApi(methods.configExport(hostIds, templateIds, groupIds, SESSIONID));
}).then(function(config) {
if (config.error) {
throw new Error('Error occurred retrieving configuration: ' + config.error.message + ': ' + config.error.data);
}
// simultaneously write to file and logout (since these are not dependent upon one another)
return Promise.all(logout(), writeToFile(config));
}).then(function() {
// success here, everything done
}, function(err) {
// upon error, try to logout and rethrow earlier error
return logout().then(function() {
throw err;
}, function() {
throw err;
});
}).then(null, function(err) {
// error here
console.log(err);
});
}
function writeToFile (config) {
return new Promise(function(resolve, reject) {
fs.writeFile('zabbix_config_export.json', JSON.stringify(config), function (err) {
if (err) {
return Promise.reject(new Error('Error writing configuration to file: ' + err));
}
resolve();
});
});
}
main();
This also makes some other important structural changes/fixes: 这还会进行其他一些重要的结构更改/修复:
Promise.all()
in two places where operations can run in parallel because they are not dependent upon one another, but the code logic wants to know when they are all done. Promise.all()
,因为它们彼此不依赖,但是代码逻辑想知道何时完成所有操作。 writeToFile()
is changed to return a promise. writeToFile()
更改为返回承诺。 logout()
function that can be safely called in several error paths so all error and success paths at least attempt the logout (if login succeeded) logout()
函数,以便所有错误和成功路径至少都会尝试注销(如果登录成功) apiVersion
because you should check !apiVersion
first. apiVersion
时,请交换两个条件,因为您应该首先检查!apiVersion
。 Promises.all
is intended to handle asynchronous functions when they run in parallel and you need to wait until they all are finished. Promises.all
用于在异步函数并行运行时处理它们,您需要等待它们全部完成。 The promises in the code you shared are not independent so you can't use Promises.all
here. 您共享的代码中的Promise不是独立的,因此您不能在此处使用
Promises.all
。 Check out this reference to see the Promises.all
usage. 查看此参考以查看
Promises.all
用法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.