【问题标题】:NodeJS: TypeError: undefined is not a function - Promise.all - Object.keysNodeJS: TypeError: undefined is not a function - Promise.all - Object.keys
【发布时间】:2017-08-26 17:57:00
【问题描述】:

我需要您的帮助,因为我得到了问题中提到的 typeError,但我不确定为什么。 我有一个看起来像这样的对象(从请求承诺返回):

{
                   "statusCode": 200,
                   "body": {
                      "BTC_USD": {
                         "buy_price": "4258",
                         "sell_price": "4265",
                         "last_trade": "4265",
                         "high": "4360",
                         "low": "4200",
                         "avg": "4260.2077946",
                         "vol": "219.32404491",
                         "vol_curr": "933982.49730504",
                         "updated": 1503767188
                      },
                      "BTC_EUR": {
                         "buy_price": "3640.1001",
                         "sell_price": "3650",
                         "last_trade": "3644.8",
                         "high": "3801.999999",
                         "low": "3622.000006",
                         "avg": "3685.0414084",
                         "vol": "94.48595035",
                         "vol_curr": "347993.56447153",
                         "updated": 1503767128
                      },
                      "BTC_RUB": {
                         "buy_price": "243511",
                         "sell_price": "244340",
                         "last_trade": "243511.49870226",
                         "high": "248786.99",
                         "low": "239630",
                         "avg": "243430.47675799",
                         "vol": "140.12303781",
                         "vol_curr": "34185015.26771479",
                         "updated": 1503767190
                      },
                      "BTC_UAH": {
                         "buy_price": "107000",
                         "sell_price": "107790",
                         "last_trade": "107790",
                         "high": "109900",
                         "low": "105354",
                         "avg": "108167.30195869",
                         "vol": "34.94251977",
                         "vol_curr": "3770330.73968614",
                         "updated": 1503767167
                      },
                      "DASH_BTC": {
                         "buy_price": "0.08528559",
                         "sell_price": "0.08644069",
                         "last_trade": "0.086196",
                         "high": "0.093364",
                         "low": "0.07043",
                         "avg": "0.0803689",
                         "vol": "1595.2753788",
                         "vol_curr": "123.76291968",
                         "updated": 1503767189
                      },
                   },
                   "request": {
                      "uri": {
                         "protocol": "https:",
                         "slashes": true,
                         "auth": null,
                         "host": "api.exmo.com",
                         "port": 443,
                         "hostname": "api.exmo.com",
                         "hash": null,
                         "search": null,
                         "query": null,
                         "pathname": "/v1/ticker/",
                         "path": "/v1/ticker/",
                         "href": "https://api.exmo.com/v1/ticker/"
                      },
                      "method": "GET",
                      "headers": {
                         "accept": "application/json"
                      }
                  }
                }

如您所见,body 有多个对象,我的目标是为每个body.keys 重新排列新布局中的信息:

Object.keys(res.body).forEach((k) => {
          result= {
            mk: 'exmo',
            name: k,
            a: res.body[k].sell_price,
            b: res.body[k].buy_price,
            c: res.body[k].last_trade,
            v: res.body[k].vol,
            t: res.body[k].vol_curr,
            l: res.body[k].low,
            h: res.body[k].high,
            sn: res.body[k].updated,
          }
        });
        return result;

但由于某种原因它不起作用...我觉得我没有正确使用 Promise.all?

这是我的完整测试代码(它重现了错误):

function exmo() {
  Promise.all(
    function () {
        var result = {};
        var res = {
                   "statusCode": 200,
                   "body": {
                      "BTC_USD": {
                         "buy_price": "4258",
                         "sell_price": "4265",
                         "last_trade": "4265",
                         "high": "4360",
                         "low": "4200",
                         "avg": "4260.2077946",
                         "vol": "219.32404491",
                         "vol_curr": "933982.49730504",
                         "updated": 1503767188
                      },
                      "BTC_EUR": {
                         "buy_price": "3640.1001",
                         "sell_price": "3650",
                         "last_trade": "3644.8",
                         "high": "3801.999999",
                         "low": "3622.000006",
                         "avg": "3685.0414084",
                         "vol": "94.48595035",
                         "vol_curr": "347993.56447153",
                         "updated": 1503767128
                      },
                      "BTC_RUB": {
                         "buy_price": "243511",
                         "sell_price": "244340",
                         "last_trade": "243511.49870226",
                         "high": "248786.99",
                         "low": "239630",
                         "avg": "243430.47675799",
                         "vol": "140.12303781",
                         "vol_curr": "34185015.26771479",
                         "updated": 1503767190
                      },
                      "BTC_UAH": {
                         "buy_price": "107000",
                         "sell_price": "107790",
                         "last_trade": "107790",
                         "high": "109900",
                         "low": "105354",
                         "avg": "108167.30195869",
                         "vol": "34.94251977",
                         "vol_curr": "3770330.73968614",
                         "updated": 1503767167
                      },
                      "DASH_BTC": {
                         "buy_price": "0.08528559",
                         "sell_price": "0.08644069",
                         "last_trade": "0.086196",
                         "high": "0.093364",
                         "low": "0.07043",
                         "avg": "0.0803689",
                         "vol": "1595.2753788",
                         "vol_curr": "123.76291968",
                         "updated": 1503767189
                      },
                   },
                   "request": {
                      "uri": {
                         "protocol": "https:",
                         "slashes": true,
                         "auth": null,
                         "host": "api.exmo.com",
                         "port": 443,
                         "hostname": "api.exmo.com",
                         "hash": null,
                         "search": null,
                         "query": null,
                         "pathname": "/v1/ticker/",
                         "path": "/v1/ticker/",
                         "href": "https://api.exmo.com/v1/ticker/"
                      },
                      "method": "GET",
                      "headers": {
                         "accept": "application/json"
                      }
                  }
                }
        Object.keys(res.body).forEach((k) => {
          result= {
            mk: 'exmo',
            name: k,
            a: res.body[k].sell_price,
            b: res.body[k].buy_price,
            c: res.body[k].last_trade,
            v: res.body[k].vol,
            t: res.body[k].vol_curr,
            l: res.body[k].low,
            h: res.body[k].high,
            sn: res.body[k].updated,
          }
        });
        return result;
    }).then((data) => {
    console.log(JSON.stringify(data, null, 3));
  })
};

exmo();

提前感谢大家的帮助!

***** 编辑 *****:[试图澄清] 我的目标是每次 forEach 迭代都获得一个对象。最终,这些对象中的每一个都会进入一个 mongo 数据库。 我使用不正确的 Promise.all(因为它需要一系列承诺)但正在寻找类似的解决方案。

【问题讨论】:

  • 请告诉我们你想得到什么输出。
  • “需要重写”不仅仅是“删除一些代码行”,pastebin.com/raw/znLHzvz7这就是你想要的吗?
  • Promise.all() 应该传递一个承诺数组。您正在向它传递一个永远不会被调用的函数。对于初学者,请完全删除 Promise.all()
  • 不要使用forEach。还有你想用result做什么?
  • 投票结束,因为这个问题还不清楚,OP 也无法澄清。

标签: javascript node.js object promise


【解决方案1】:

由于您的代码全部集中在一起,您的问题有点复杂,所以在这里我将其分开。

此函数模拟您的服务器响应作为示例向您展示如何管理承诺。

function getData() {
  return new Promise((resolve, reject) => {

    // Parse the returned data
    resolve(JSON.parse(res));
  });
}

然后您需要转换数据。在这里你可以使用map 来迭代obj 而不是forEach

function mapData(obj) {
  return Object.keys(obj.body).map((k) => {
    return {
      mk: 'exmo',
      name: k,
      a: res.body[k].sell_price,
      b: res.body[k].buy_price,
      c: res.body[k].last_trade,
      v: res.body[k].vol,
      t: res.body[k].vol_curr,
      l: res.body[k].low,
      h: res.body[k].high,
      sn: res.body[k].updated
    }
  });
}

然后你可以简单地调用getData,mapData,然后输出结果。您不希望在此处使用Promise.all,因为该方法仅接受一组承诺。

getData()
  .then(mapData)
  .then(data => console.log(JSON.stringify(data, null, 3)));

DEMO(注意,此演示使用您已解析的 obj,因此不会在 getData 中重新解析它)。

【讨论】:

  • 你为什么在这里使用promise?仍然没有显示可以从 Promise 中受益的异步操作。如果这里涉及到一个http请求,那么无论如何都应该在较低的级别上promisified。
  • 在问题中:“我有一个对象(从请求承诺返回)”@jfriend00。
  • @jfriend00,我不知道您评论的第二个编辑部分是什么意思。也许你可以澄清一下。
  • 那么,如果已经有异步操作的承诺,为什么还要创建另一个承诺。这是一种反模式。从 OP 似乎已经放弃并且没有澄清开始,这是一个糟糕的问题。它可能应该被否决和/或关闭。
  • 从我的回答中:“这个函数模仿你的服务器响应:”我不是凭空创造一个新的承诺 - 我正在使用一个简化的例子来说明如何服务器响应然后显示如何管理该响应。
【解决方案2】:

如您所见,您在循环forEach() 中一遍又一遍地重新分配result,最后的return 只能返回body 中最后一个键的信息。
您需要做的是将具有相同键的所有值放入一个数组中(也许?)。 或者以更简单的方式:转置整个表格。
因此,您必须首先声明一堆Array

// init
let result = { };
let keys = ['buy_price', 'sell_price', /* etc. */];
keys.forEach(k => result[k] = []);

// gathering informations
Object.keys(res.body).forEach(name =>
    Object.keys(res.body[name]).forEach(k => result[k].push(res.body[name][k]))
);

现在您可以通过索引从result 轻松获取您的信息。

如果你想通过它们的原始名称来索引它们,你可以先将result初始化为一堆Object,然后在内部forEach()中使用name而不是直接push() .

Object.keys(res.body[name]).forEach(k => result[k][name] = res.body[name][k])

这对“转置”整个表格更有意义。

【讨论】:

  • 嘿@Nianyi Wang!感谢您的回答!对不起,这是我的错,我想我的问题不够精确。你明白了逻辑,但我正在寻找一个输出,它可以为每次结果迭代提供一个新的“不同”对象。目标是将信息推送到 mongodb。
【解决方案3】:

Promise.all(iterable) 它接受一个可迭代的对象,例如数组或字符串。

我修改了你的代码,它给出了输出。 注意:- 你的代码逻辑我没有改变,它给出的结果是你的逻辑。

function exmo() {
  var data = (function () {
        var result = {};
        var res = {
                   "statusCode": 200,
                   "body": {
                      "BTC_USD": {
                         "buy_price": "4258",
                         "sell_price": "4265",
                         "last_trade": "4265",
                         "high": "4360",
                         "low": "4200",
                         "avg": "4260.2077946",
                         "vol": "219.32404491",
                         "vol_curr": "933982.49730504",
                         "updated": 1503767188
                      },
                      "BTC_EUR": {
                         "buy_price": "3640.1001",
                         "sell_price": "3650",
                         "last_trade": "3644.8",
                         "high": "3801.999999",
                         "low": "3622.000006",
                         "avg": "3685.0414084",
                         "vol": "94.48595035",
                         "vol_curr": "347993.56447153",
                         "updated": 1503767128
                      },
                      "BTC_RUB": {
                         "buy_price": "243511",
                         "sell_price": "244340",
                         "last_trade": "243511.49870226",
                         "high": "248786.99",
                         "low": "239630",
                         "avg": "243430.47675799",
                         "vol": "140.12303781",
                         "vol_curr": "34185015.26771479",
                         "updated": 1503767190
                      },
                      "BTC_UAH": {
                         "buy_price": "107000",
                         "sell_price": "107790",
                         "last_trade": "107790",
                         "high": "109900",
                         "low": "105354",
                         "avg": "108167.30195869",
                         "vol": "34.94251977",
                         "vol_curr": "3770330.73968614",
                         "updated": 1503767167
                      },
                      "DASH_BTC": {
                         "buy_price": "0.08528559",
                         "sell_price": "0.08644069",
                         "last_trade": "0.086196",
                         "high": "0.093364",
                         "low": "0.07043",
                         "avg": "0.0803689",
                         "vol": "1595.2753788",
                         "vol_curr": "123.76291968",
                         "updated": 1503767189
                      },
                   },
                   "request": {
                      "uri": {
                         "protocol": "https:",
                         "slashes": true,
                         "auth": null,
                         "host": "api.exmo.com",
                         "port": 443,
                         "hostname": "api.exmo.com",
                         "hash": null,
                         "search": null,
                         "query": null,
                         "pathname": "/v1/ticker/",
                         "path": "/v1/ticker/",
                         "href": "https://api.exmo.com/v1/ticker/"
                      },
                      "method": "GET",
                      "headers": {
                         "accept": "application/json"
                      }
                  }
                }
        Object.keys(res.body).forEach((k) => {
          result= {
            mk: 'exmo',
            name: k,
            a: res.body[k].sell_price,
            b: res.body[k].buy_price,
            c: res.body[k].last_trade,
            v: res.body[k].vol,
            t: res.body[k].vol_curr,
            l: res.body[k].low,
            h: res.body[k].high,
            sn: res.body[k].updated,
          }
        });
        return result;
    });
    
    Promise.all([data()]).then((data) => {
    console.log(JSON.stringify(data, null, 3));
  })
};

exmo();

<!-- begin snippet: js hide: false console: true babel: false -->

【讨论】:

  • 嘿@Srinath!这也是我想出的,但是因为我有 forEach 循环,所以它会产生最后一个被迭代的结果。这不正是我要找的。我想从每个结果迭代中生成一个“新”对象。
猜你喜欢
  • 2015-06-24
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
  • 2014-08-15
  • 2015-01-14
  • 2014-07-06
  • 2014-09-01
  • 2020-02-15
相关资源
最近更新 更多