【问题标题】:building an object based on result of promise call根据 promise 调用的结果构建对象
【发布时间】:2017-01-26 12:10:07
【问题描述】:

我正试图围绕 Promises(我知道这是一个常见的主题)来思考。我有基本的想法,但我在实施它们时遇到了麻烦。

我正在尝试构建一个对象,该对象根据目录的内容公开一组函数。我正在使用 bluebird 来承诺 fs 库。然后读入dir的文件,构建对象,返回结果。

    var Promise = require('bluebird'),
    fs = Promise.promisifyAll(require('fs'));

    var services = {};

    return fs.readdirAsync('./path/to/file/')
        .each(function (filename) {
            //trim off the file extension and assign the export function
            services[filename.replace(/\.[^/.]+$/, "")] = function(request) {
                request.esbOperation = filename;
                otherFunctionCall(request);
            }
        })
        .then(function() {
            return {services: services};
        })
        .catch(function(err){
             console.log(err);
        });

我尝试了很多方法,但返回的对象通常如下所示:

Promise {
  _bitField: 167772160,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: 
   { services: 
      { function1: [Function],
        function2: [Function],
        function3: [Function],
      },
  _promise0: undefined,
  _receiver0: undefined }

如何在履行处理程序中获得结果? 如何让它返回已解决的对象而不是 Promise 对象(我在各个地方尝试过解决/拒绝,但我做错了)?

【问题讨论】:

  • 你没有。你返回承诺(这是你所看到的,因为它已经在工作了)。这就是他们的目的。您不能立即返回将在未来计算的结果。
  • @Bergi 为什么在拒绝处理程序中?
  • @GForce 我无法说明为什么您的对象存储在_rejectionHandler0 属性中,但您不应该尝试从promise 的内部属性中获取值。你应该打电话给.then() 和/或.catch() 来处理它。
  • @GForce 因为 Bluebird 对内存非常谨慎。你不应该关心它的内部表示。
  • 似乎几乎是stackoverflow.com/questions/14220321/…的复制品

标签: node.js promise


【解决方案1】:

您无法返回已解析的对象。这就是重点。您获取的数据在您的函数返回很久之后才可用。

所以你的两个主要选择是:

  1. 接受你有一个返回承诺的函数(这不是一件坏事!)。想要获取分辨率值的消费者可以调用.then()就可以了。

  2. 让你的函数接受回调,并让你的函数中的 promise 调用它。这种首先违背了使用 Promise 的目的,但会使您的函数签名更加“类似节点”:

function myFunction(callback) {
    var Promise = require('bluebird'),
    fs = Promise.promisifyAll(require('fs'));

    var services = {};

    fs.readdirAsync('./path/to/file/')
        .each(function (filename) {
        //trim off the file extension and assign the export function
            services[filename.replace(/\.[^/.]+$/, "")] = function(request) {
                request.esbOperation = filename;
                otherFunctionCall(request);
            }
        })
        .then(function() {
            callback(null, {services: services});
        }, function(err){
            callback(err);
        });
}

正如 Bergi 所指出的,由于您使用的是 Bluebird,因此对仍然达到相同目的的 #2 选项的改进是使用 .asCallback 而不是 .then

这里有几点需要注意:

  • 在此选项中,您仍然需要 then() 来获取管道中的 {services: services} -object,以便将其传递给回调
  • 在函数的第 6 行有一个 return 语句。这是因为.asCallback() 返回了一个承诺,它允许您的函数的调用者选择是要使用返回的承诺还是使用回调。
function myFunction(callback) {
    var Promise = require('bluebird'),
    fs = Promise.promisifyAll(require('fs'));

    var services = {};

    return fs.readdirAsync('./path/to/file/')
        .each(function (filename) {
        //trim off the file extension and assign the export function
            services[filename.replace(/\.[^/.]+$/, "")] = function(request) {
                request.esbOperation = filename;
                otherFunctionCall(request);
            }
            return {services: services};
        })
        .then(function() { return {services: services} })
        .asCallback(callback);
}

【讨论】:

  • 我挂断的部分原因是结果在拒绝处理程序中。这让我觉得我做错了什么。
  • 由于 OP 使用的是 Bluebird,你应该使用 .asCallback(callback) 而不是 then().catch() 的事情
  • @GForce 正如我已经说过的,你应该停止担心 promise 的内部结构并尝试实际使用它。据我所知,你没有做错任何事。
  • @Bergi 谢谢,我不知道这个功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多