【问题标题】:Continue fetching data until result is empty array继续获取数据,直到结果为空数组
【发布时间】:2019-09-05 02:47:40
【问题描述】:

我正在使用 Selly API 并尝试获取所有产品,但是 Selly API 对产品进行分页。

所以我需要获取所有产品并添加到一个数组中,然后通过 JSON 输出结果。

const base64 = require('base-64');
import fetch from 'isomorphic-unfetch';

export default async (req, res) => {
    res.setHeader('Content-Type', 'application/json');
    try {
        request('products')
            .then(data => data.json())
            .then(json => res.status(200).end(JSON.stringify(json)));
    } catch(err) {
        res.end(JSON.stringify({
            "error": err
        }));
    }
}

const getToken = () => {
    return base64.encode(`${process.env.api.email}:${process.env.api.key}`);
}

const request = async (endpoint = '', page) => {
    const options = {
        headers: {
            Authorization: `Basic ${getToken()}`,
            'User-Agent':  `${process.env.api.email} - https://example.com`
        }
    }
    return fetch(`https://selly.io/api/v2/${endpoint}?page=${page}`, options);
}

我正在尝试获取https://selly.io/api/v2/products?page=${page},直到返回结果为空数组[]

我的尝试是这样的:

const repeatedRequest = async (data, endpoint) => {
    let i = 1;
    while (data.length > 0) {
        console.log(data);
        await request(endpoint, i).then((res) => {
            data.push(res);
            i++;
        });
    }
    return data;
}

但是这不起作用,因为返回结果是一个空数组。我也很困惑如何与以下 sn-p 一起执行此操作:

request('products')
    .then(data => data.json())
    .then(json => res.status(200).end(JSON.stringify(json)));

我将如何在这个函数中工作?

我该怎么做?

【问题讨论】:

  • 那个循环看起来很假。 while (data.length >0) /*push something into data*/。假设它开始了,这似乎是一个无限循环。 data 只会越来越长,对吧?我看不出data.length 可能会变成0。我期待一个退出条件,其中请求检测到失败(在这种情况下,res 可能是未定义的?)然后 that 导致循环退出(可能只是在 res 未定义时导致它返回。)还是我误解了?
  • Wyck 我想我和你一样困惑。你会怎么做?
  • 问题是,正如 Wyck 所说,data.length 将始终大于 0,假设它开始为非空(如果它开始为空,则循环将永远不会运行)。您似乎想检查实际 API 响应 res 的长度是否为 0,而不是 data,这是您累积所有响应的地方。
  • jacob,介意提交答案吗?我很困惑。
  • 我认为您可以解决这个问题 - 也许尝试添加更多控制台日志记录以进行调试会有所帮助。目前在while 循环中有一个console.log - 当你运行它时,它会打印出什么吗?

标签: javascript node.js reactjs next.js


【解决方案1】:

您(在评论中)询问了一个子问题,即如何设置循环以一遍又一遍地调用请求函数以获取结果,直到没有更多结果为止。我将尝试以一种最小且通用的方式在这里回答您的子问题,希望对您和其他人有用。

这是一种单独设置异步循环机制的方法。方法总是不止一种。 ;)

我将制作几个实用函数,让我能够简洁地表达解决方案。

  1. 我需要一个假的request 函数,它会返回一些结果,然后返回一些虚假的结果。我会打电话给fakeRequest
  2. 我需要一种通用方法来调用具有不断增加的整数索引参数的异步函数,直到它返回一些错误的东西作为 异步生成器函数。我会打电话给iterateAllAsync
  3. 我需要一种通用方法将异步生成器函数的所有结果合并到一个数组中。本质上是Array.from 的异步版本。我会打电话给arrayFromAsync

然后你可以说:i = 0 开始发出虚假请求并递增i 直到它不返回任何内容,然后将所有这些结果作为数组返回

...您可以(大致)将其表达为:arrayFromAsync(iterateAllAsync(fakeRequest))。在实践中我可能会添加一个 lambda 来向您展示如何将一些额外的参数 curry 到 fakeRequest 中,但这是它的基本结构。

这就是全部内容:

// An example fake request function
const fakeRequest = async (endpoint, i) => {
  const kNumberOfFakeResultsToReturn = 3;
  if (i >= kNumberOfFakeResultsToReturn) return;
  return { content: `fake payload #${i} from ${endpoint}` };
};

// A general purpose utility function:
// yields results of calling fn(i) with ever increasing i until it returns something falsey
async function* iterateAllAsync(fn, i = 0) {
  while (true) {
    let res = await fn(i)
    if (!res) return;
    yield res;
    ++i;
  }
}

// A general purpose utility function:
// returns an async generator's results as an array
const arrayFromAsync = async (it) => {
  let results = [];
  for await (let res of it) {
    results.push(res);
  }
  return results;
}

// Here's where we describe what we want done:
arrayFromAsync(iterateAllAsync((i) => fakeRequest('fakeEndpoint', i)))
  .then(console.log);

【讨论】:

  • 这段代码在arrayFromAsync 中给我一个错误,因为res 没有定义。应该是for await (let res of it)
  • @parsley72 好收获!固定。
猜你喜欢
  • 2018-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-02
  • 2018-12-18
  • 2017-05-02
  • 1970-01-01
相关资源
最近更新 更多