我有一个我一直在研究的NodeJS脚本,但我遇到的最大问题是链接所有这些承诺不仅难看,而且随着时间的推移难以维护。
我想使用Promise.all()
方法将这些单独的promises转换为一个,但我不确定如何使用此方法获得相同的功能并将变量从一个promise分配给另一个promise。
例如,我的第二个承诺:methods.login()
返回几乎所有其他承诺中使用的sessionId。我如何使用Promise.all()
??
这是我目前的代码:
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();
答案 0 :(得分:2)
您可以对可以并行运行的操作使用Promise.all()
,但不能对必须按特定顺序执行的操作使用getApiVersion
Login to session
In parallel (getHostGroups, getTemplates, getHosts)
configExport previous results
In parallel (logout, writeToFile)
。
在查看代码时,您似乎确实有几个地方可以并行执行某些操作,但并非所有操作都可以通过这种方式完成。看来你可以按照这个一般顺序做事:
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();
这可以这样实现:
Promise.all()
这也使得一些其他重要的结构变化/修复:
writeToFile()
,其中操作可以并行运行,因为它们不相互依赖,但代码逻辑想要知道它们何时完成。logout()
已更改为返回承诺。apiVersion
函数,以便所有错误和成功路径至少尝试注销(如果登录成功)!apiVersion
时交换这两个条件,因为您应先检查Visual Studio 2015
。答案 1 :(得分:1)
Promises.all
用于在并行运行时处理异步函数,您需要等到它们全部完成后才能运行。您共享的代码中的承诺不是独立的,因此您无法在此处使用Promises.all
。查看this reference以查看Promises.all
用法。