node.js - 在循环中请求 JSON

标签 node.js object request

我无法在 API 请求返回的对象之间正确浏览。

基本上,我有一个数组(tickerArr,其中包含从另一个请求获取的 25 个元素),我将其用于另一个请求的 forEach 循环。

代码如下:

var request = require('request');
var async = require('async');
var fs = require('fs')

var getTickerList = require('./getTickerList').getTickerList;
var unixTimeStamp = new Date().toISOString();

async function getTickerInfo() {

  var tickerArr = await getTickerList;
  var arrLength = tickerArr.length;
  var init = 0;

  console.log(`${arrLength} to process to the batchfile...`);
  var getTickerInfo = new Promise((resolve, reject) => {
    async.forEach(tickerArr, (item, callback) => {
      request({
        url:`https://api.kraken.com/0/public/Ticker?pair=${item}`,
        json: true
      }, (error, response, body) => {
        var tickerInfo = JSON.stringify(body.result)
        fs.appendFile(`./modules/batches/${unixTimeStamp}batch.json`, tickerInfo, (err) => {
          if (err) throw err;
          init ++;
          var progress = Math.round(init / arrLength * 100);
          console.log(`[${progress}%] - ${item} successfully added!`);
        });
         resolve();
      })
    });
  });
}

getTickerInfo()

不幸的是,即使请求正常工作,返回的对象也有一个特定的路径:

  • Error: []
  • Result:
    • Pair(x):
      • a: [1, 2, 3]
      • b: [1, 2, 3] ect...

您可以找到从请求 here 返回的信息的确切示例:

{
    "error": [],
    "result": {
        "XXBTZEUR": {
            "a": ["2212.31000", "3", "3.000"],
            "b": ["2212.21100", "1", "1.000"],
            "c": ["2212.31000", "0.15800000"],
            "v": ["4999.06419498", "9993.55448658"],
            "p": ["2206.04624", "2181.36028"],
            "t": [15065, 29524],
            "l": ["2167.00000", "2122.92000"],
            "h": ["2239.00000", "2239.00000"],
            "o": "2184.99000"
        }
    }
}

唯一的问题是:我想将从请求中获得的对象“转换”为另一个对象(只是安排一些东西,最重要的是:将“Pair(x)”属性作为名称键的值),但由于我事先不知道该对(我的 tickerArray 中的值足以发出请求,但显然不对应于引用该对象),我无法访问结果中包含的信息来操作它。

有人有什么想法吗?

提前致谢!

最佳答案

您的问题有多个层次,也许最好先将任务分解为其组成部分。

  1. 调用 Kraken REST API 并解包响应
  2. 创建小型、可组合函数
  3. 将对象转换为新布局
  4. 将结果写入文件

0。前言

既然你想使用 await,首先要知道这是“等待 promise 解析”的语法糖。 async 是在函数内启用 await 语义的关键字。

因此,考虑到这个 promise 返回函数:

function foo() {
    return Promise.resolve('some value');
}

这个:

async function worker() {
    var fooResult = await foo();
    console.log(fooResult);
}
worker();

还有这个:

foo().then(function worker(fooResult) {
    console.log(fooResult);
});

实际上是同一件事。 (与往常一样,它比这更复杂一些,但这就是要点。)

由于我们在这里使用 Promise,最明智的做法是使用也使用 Promise 的库。 requestrequest-promise 对应部分,所以让我们使用它。

var request = require('request-promise');

1。调用 Kraken REST API 并解包响应

发出 HTTP 请求并分解响应(errresult 部分)对于所有 API 端点都是相同的,因此我们可以编写一个函数来处理此任务。

function getFromApi(endpoint, params) {
    return request({
        url: "https://api.kraken.com/0/public/" + endpoint,
        qs: params,
        json: true
    }).then(function (data) {
        if (data.error && data.error.length) {
            throw new Error(`API error xyz for ${endpoint} with params ...`);
        }
        return data.result;
    });
}

此函数的用户根​​本不必处理err,并且可以直接访问结果

2。创建小型、可组合的函数

我们的 getFromApi() 函数返回一个 Promise,因此我们可以在各种 API 端点的包装器中重用它:

function getTickerList() {
    return getFromApi("TickerList"); // ...or something like that
}

function getSingleTicker(pair) {
    return getFromApi("Ticker", {pair: pair}).then(transformTicker);
}

function getTickerInfo(tickerList) {
    return Promise.all(tickerList.map(getSingleTicker));
}

请注意,就像在 getFromApi() 中一样,我们可以使用 Promise#then 来修改操作的整体输出。

getTickerInfo() 接受股票代码名称数组。它使用 Array#map 并行运行所有 API 请求,并使用 Promise#all 等待总体结果。并行获取和转换多个结果的相当复杂的操作组成了一个非常简单的单行代码。

3。将对象转换为新布局

transformTicker() 旨在接受 {"XXBTZEUR": {"a": [...], ... }} 形式的对象并返回其转换后的变体。

function transformTicker(ticker) {
  var result = {};

  // ...massage ticker into desired form
  Object.keys(ticker).forEach( pair => {
      Object.keys(ticker[pair]).forEach( k => {
          result[k] = { /* ... */ };
      });
  });

  return result;
}

4。将结果写入文件

附加到 JSON 文件不起作用。 JSON 只能作为一个整体来读写。让我们获取股票名称列表、关联股票并将结果写入文件。

async function worker() {
    var tickerList = await getTickerList();
    var tickerInfo = await getTickerInfo(tickerList);
    var filename = `./modules/batches/${new Date().toISOString()}batch.json`;

    fs.writeFile(filename, JSON.stringify(tickerInfo), (err) => {
        if (err) throw err;
        console.log("Done");
    });
}

worker();

您可以切换使用 fs 模块的 promise 版本 ( see Bluebird#promisifyAll ),因为普通版本需要连续回调,从而再次破坏了良好的 async/await 语义。

使用 Promisified fs 模块,worker 可能如下所示:

async function worker() {
    var tickerList = await getTickerList();
    var tickerInfo = await getTickerInfo(tickerList);
    var filename = `./modules/batches/${new Date().toISOString()}batch.json`;

    await fs.writeFileAsync(filename, JSON.stringify(tickerInfo));
    console.log("Done");
}

关于node.js - 在循环中请求 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45351191/

相关文章:

node.js - nodeJS - 巨大的字符串文件故障

javascript - 在nodejs中使用axios检查url重定向

ios - 检查 ios 模拟器/设备中的 http 请求

javascript - Angular 5 w/Angular Material - 从 ngFor 中提取对象属性以在组件中使用

javascript - 如果存在键名数组,则更改对象的深层嵌套键值

javascript - 如何在非常快速地发出大量请求时修复 "Socket Hangup Error "

python - POST 请求文件 python-requests

javascript - 使用 Node 请求模块获取响应 header

javascript - Node.js http.get 作为函数

Java undefined object