繁体   English   中英

NodeJS将Promises转换为Promise.all

[英]NodeJS Convert Promises to Promise.all

我有一个正在工作的NodeJS脚本,但是最大的问题是,将所有这些诺言链接起来不仅看起来很丑,而且随着时间的推移很难维护。

我想使用Promise.all()方法将这些单独的承诺转换为一个,但是不确定如何使用该方法获得相同的功能并将变量从一个承诺分配给另一个承诺。

例如,我的第二个Promise: methods.login()返回一个几乎在所有其他Promise中使用的sessionId。 我将如何使用Promise.all()分配该变量并将其传递给其他相关的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();

您可以对可以并行运行的操作使用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();

这还会进行其他一些重要的结构更改/修复:

  1. 每当您有拒绝/捕获处理程序时,如果您既不返回被拒绝的承诺,也不从该处理程序中抛出,则承诺链将继续运行,这不是您想要的,并且您几乎在所有拥有的拒绝处理程序中都这样做。
  2. 无需为每一个承诺都设置拒绝处理程序。 如果您只是打算以任何拒绝方式终止链,则只需确保拒绝原因是描述性的,并在链末尾将所有故障记录在一个位置即可。
  3. 这在两个地方可以并行运行操作的地方使用Promise.all() ,因为它们彼此不依赖,但是代码逻辑想知道何时完成所有操作。
  4. writeToFile()更改为返回承诺。
  5. 创建一个可以在多个错误路径中安全调用的logout()函数,以便所有错误和成功路径至少都会尝试注销(如果登录成功)
  6. 检查apiVersion时,请交换两个条件,因为您应该首先检查!apiVersion

Promises.all用于在异步函数并行运行时处理它们,您需要等待它们全部完成。 您共享的代码中的Promise不是独立的,因此您不能在此处使用Promises.all 查看此参考以查看Promises.all用法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM