Node.js异步模块要求

时间:2018-06-21 17:22:34

标签: node.js express require

我对依赖第一个require()的基于Express的node.js应用程序有疑问。这是我的第一个node.js应用程序。第一个require()命中AWS ec2参数存储以收集数据库的凭证。在此需求以异步方式解决之前,我无法建立与数据库的连接。

我发现做到这一点的最好方法是导出一个回调,并将其余的require()语句包装在第一个require()的回调中。 这是不好的做法吗?

//app.js

var appConfig = require('./config/appconfig');

appConfig.fetchAppConfig(function(err, result) {
    if(err) {
        console.log(err);
        console.error("Server failed to startup. Config parameters not available.");
    }
    else {
        var express = require('express');
        var path = require('path');
        var cookieParser = require('cookie-parser');
        ...
        app.use(bodyParser.json());
        etc
        ...

//appConfig.js

module.exports = function fetchAppConfig(callback) {
    getCredentials(function(err, result) {
        if(err) {
            console.log(err);
            callback(err);
        } else {
            awsLogin.paramStoreService(result).then(
                data => {
                    appConfig = decodeAppConfig(data.Parameter.Value);
                    callback(null, appConfig);
                }
            ).catch(
                error => {
                    console.error(error);
                    callback(err);
                }
            )
        }
    })
}

我错过了一个更简单的选择吗?

让我更好地使用这种逻辑将配置提取到部署代码中的某处?

2 个答案:

答案 0 :(得分:0)

我将定义几个函数,一个函数用于请求凭据,而另一个函数则在检索到凭据后连接到数据库。您可以使用async模块的series函数来轻松地控制应用程序的流程。

从文档中:

  

依次运行任务集合中的功能,每个功能都在运行   一旦上一个功能完成。如果有任何功能   系列将错误传递给其回调,不再运行任何函数,并且   立即使用错误值调用回调。除此以外,   任务完成后,回调会收到一系列结果。

这是一个例子:

var async = require('async');

function getCredentials(callback) {
    callback(null, {
        user: 'hello',
        pass: 'world',
    });
};

function connectToDatabase(callback, creds) {
    console.log('Connecting to database => ' + JSON.stringify(creds));

    callback(null, 'Done');
};

async.series([
    getCredentials,
    connectToDatabase,
],
function(err, results) {
    console.error(err);
    console.log(results);
});

答案 1 :(得分:0)

直到节点支持顶级等待,以下是我针对此确切用例使用的解决方案。

// index.js

(async () => {
  await require('./config').initialize();
  require('./app');
})();

// config.js

const _ = require('lodash');

const secretKeys = ['secret1', 'secret2']; 

const parameterHierarchyPrefix = `/${process.env.NODE_ENV}/app/`;
const getParamNameWithoutHierarchy = name => _.replace(name, new RegExp(`${parameterHierarchyPrefix}(.*)`), '$1');

const config = {};
config.initialize = async (callback = () => {}) => {
  try {
    // initialize aws sdk and ssm
    const AWS = require('aws-sdk');
    AWS.config.update({
      region: 'us-west-2',
      accessKeyId: S3_ACCESS_KEY,
      secretAccessKey: S3_SECRET,
    });
    const ssm = new AWS.SSM();

    // map secret keys to lowercase
    const secretNames = _.map(secretKeys, key => `${parameterHierarchyPrefix}key`);

    // this api only allows fetching 10 params per call
    const secretFetchBatches = _.chunk(secretNames, 10);

    // fetch secrets from aws parameter store
    let secrets = {};
    for (let i = 0; i < _.size(secretFetchBatches); i += 1) {
      const parameters = await ssm.getParameters({
        Names: secretFetchBatches[i],
        WithDecryption: true,
      }).promise();
      secrets = {
        ...secrets,
        ..._.zipObject(_.map(parameters.Parameters, ({ Name }) => ([getParamNameWithoutHierarchy(Name)])), _.map(parameters.Parameters, 'Value')),
      };
    }

    // write the secrets into the config object
    _.each(secrets, (v, k) => constants[k] = v);

    // invoke the callback
    callback();
  } catch (e) {
    throw e
  }
};

module.exports = config;