我无法在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()
不幸的是,即使请求正常工作,返回的对象也有一个特定的路径:
- 错误:[]
- 结果:
- 对(x):
- a:[1,2,3]
- b:[1,2,3]等......
您可以找到从请求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)'属性作为名称键的值)但是因为我没有&#39 ; t事先知道对(我tickerArray
中的值足以发出请求但显然不对应引用对象),我无法访问结果中包含的信息来操纵它。
有人有任何想法吗?
提前致谢!
答案 0 :(得分:3)
您的问题有多个级别,也许最好先将任务分解为其组成部分。
由于您希望使用await
,首先要知道的是,这是#34的语法糖;等待承诺解决"。 async
是在函数内启用await
语义的关键字。
所以给出了这个承诺返回功能:
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);
});
实际上是一回事。 (一如既往,它比这复杂一点,但这是它的要点。)
由于我们在这里使用promises,最明智的做法是使用也使用promises的库。 request
有request-promise
反对,所以让我们使用它。
var request = require('request-promise');
发出HTTP请求并分解响应(err
和result
部分)对所有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
并且可以直接访问result
。
我们的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
允许等待整体结果。获取和转换多个并行的相当复杂的操作组成了一个非常直接的单行。
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;
}
附加到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
模块的promisified版本(see Bluebird#promisifyAll
),因为普通版本通过要求延续回调再次打破了漂亮的async / await语义。
使用已宣传的fs
模块,工作人员可能如下所示:
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");
}