从node.js中的回调中导出值

时间:2017-06-27 22:41:48

标签: node.js

我正在构建一个小型node.js网站,其中包含一个用户界面,其中包含一个包含国家/地区列表的下拉列表。

以前,国家列表是用json文件硬编码的,我会读到:

exports.countries = require('./json/countries.json');

然后我意识到当我可以从mongodb数据库对列表进行distinct查询时,我不应该像这样硬编码。

db.collection.distinct('c', {}, function(err, data) {
  // something
});

但接下来是如何在该回调函数中提取data变量的值的问题。我发现这有效:

db.collection.distinct('c', {}, function(err, data) {
  if (err) {
    throw Error('mongodb problem - unable to load distinct values');
  } else {
    exports.countries = data;
  }
});

我是node.js的新手,这对我来说似乎很可疑。这是好的代码吗?使用发电机或承诺更好吗?如果我想使用发电机或承诺来做这件事,我该怎么做?

使用它的最终结果是在模板中。 ref.countries是使用我的fishy代码的国家/地区的实际列表。如果我有承诺而不是国家列表,我将如何更改此代码?

  <% ref.countries.forEach(function(c) { -%>
  <option value="<%= c %>">
    <%= ref.isoCodes[c] -%>
  </option>
  <% }); -%>

我使用的是节点v6.10.3。

2 个答案:

答案 0 :(得分:0)

你说的出口&#34;工作&#34;是不可能使用的,因为加载模块的代码不知道何时实际设置了exports.countries值,因为它是在异步调用中设置的,将在未来完成某些不确定的时间。此外,您无法处理该函数中的任何错误。

这样做的现代方法是导出一个函数,该函数在被调用时返回一个解析为数据的promise(或带有错误的拒绝)。加载模块的代码,然后调用导出的函数,获取promise,在promise上使用.then()并使用.then()处理程序中的数据。这可能看起来像这样:

function getCountries() {
    return new Promise(function(resolve, reject) {
        db.collection.distinct('c', {}, function(err, data) {
          if (err) {
            reject(err);
          } else {
            resolve(data);
          }
        });
    }
}

module.exports.getCountries = getCountries;

然后调用者会这样做:

const myModule = require('myModule');
myModule.getCountries().then(function(countries) {
    console.log(countries);
    // use country data here
}).catch(function(err) {
    // deal with error here
});

目前,node.js的大多数数据库都内置了一定程度的承诺支持,因此您不必像上面所示那样围绕数据库函数创建自己的承诺包装,而是可以直接使用promise。从数据库引擎返回。它的工作原理特定于您使用的特定数据库/版本。

如果您在模板渲染操作中使用国家/地区列表,则必须获取国家/地区列表(以及模板渲染所需的任何其他数据),并且仅在所有数据时调用res.render()已成功检索。这可能还会导致在检索到必要数据时出错时应该执行的操作。在这种情况下,您通常会回复页面请求的5xx错误代码,并且可能希望呈现某种错误页面,以便通知最终用户错误。

答案 1 :(得分:0)

我正在使用Node 6.10,所以我没有异步并等待,但如果我这样做,他们会帮助我:

https://developers.google.com/web/fundamentals/getting-started/primers/async-functions

相反,我可以使用asyncawait库:

https://github.com/yortus/asyncawait

代码如下所示:

var async = require('asyncawait/async');
var await = require('asyncawait/await');

const db = require('_/db');

function getDistinctValues(key) {
  return new Promise((resolve, reject) => {
    db.collection.distinct(key, {}, function(err, data) {
      if (err) {
        throw Error('mongodb problem - unable to load distinct values');
      } else {
        resolve(data);
      }
    });
  });
};

async(function () {
    exports.countries = await(getDistinctValues('c'));
    exports.categories = await(getDistinctValues('w'));
})();

现在我可以确保ref.countriesref.categories在加载后可用。