简体   繁体   English

NextJS API 路由在收到数据之前返回?

[英]NextJS API Route Returns Before Data Received?

I'm not sure what's going on here.我不确定这里发生了什么。 I have set up an API route in NextJS that returns before the data has been loaded.我在 NextJS 中设置了一个 API 路由,该路由在加载数据之前返回。 Can anyone point out any error here please?任何人都可以在这里指出任何错误吗?

I have this function that calls the data from makeRequest():我有这个 function 从 makeRequest() 调用数据:

export async function getVendors() {
  const vendors = await makeRequest(`Vendor.json`);
  console.log({ vendors });
  return vendors;
}

Then the route: /api/vendors.js然后路由:/api/vendors.js

export default async (req, res) => {
  const response = await getVendors();
  return res.json(response);
};

And this is the makeRequest function:这是makeRequest function:

const makeRequest = async (url) => {
  // Get Auth Header
  const axiosConfig = await getHeader();

  // Intercept Rate Limited API Errors & Retry
  api.interceptors.response.use(
    function (response) {
      return response;
    },
    async function (error) {
      await new Promise(function (res) {
        setTimeout(function () {
          res();
        }, 2000);
      });

      const originalRequest = error.config;

      if (error.response.status === 401 && !originalRequest._retry) {
        token[n] = null;
        originalRequest._retry = true;
        const refreshedHeader = await getHeader();
        api.defaults.headers = refreshedHeader;
        originalRequest.headers = refreshedHeader;
        return Promise.resolve(api(originalRequest));
      }
      return Promise.reject(error);
    }
  );

  // Call paginated API and return number of requests needed.
  const getQueryCount = await api.get(url, axiosConfig).catch((error) => {
    throw error;
  });
  const totalItems = parseInt(getQueryCount.data['@attributes'].count);
  const queriesNeeded = Math.ceil(totalItems / 100);

  // Loop through paginated API and push data to dataToReturn
  const dataToReturn = [];

  for (let i = 0; i < queriesNeeded; i++) {
    setTimeout(async () => {
      try {
        const res = await api.get(`${url}?offset=${i * 100}`, axiosConfig);
        console.log(`adding items ${i * 100} through ${(i + 1) * 100}`);
        const { data } = res;
        const arrayName = Object.keys(data)[1];
        const selectedData = await data[arrayName];
        selectedData.map((item) => {
          dataToReturn.push(item);
        });

        if (i + 1 === queriesNeeded) {
          console.log(dataToReturn);
          return dataToReturn;
        }
      } catch (error) {
        console.error(error);
      }
    }, 3000 * i);
  }
};

The issue that I'm having is that getVendors() is returned before makeRequest() has finished getting the data.我遇到的问题是 getVendors() 在 makeRequest() 完成获取数据之前返回。

Looks like your issue stems from your use of setTimeout .看起来您的问题源于您对setTimeout的使用。 You're trying to return the data from inside the setTimeout call, and this won't work for a few reasons.您正在尝试从setTimeout调用中返回数据,但由于某些原因,这将不起作用。 So in this answer, I'll go over why I think it's not working as well as a potential solution for you.因此,在这个答案中,我将 go 解释为什么我认为它对您来说不起作用以及潜在的解决方案。

setTimeout and the event loop setTimeout 和事件循环

Take a look at this code snippet, what do you think will happen?看看这段代码片段,你认为会发生什么?

 console.log('start') setTimeout(() => console.log('timeout'), 1000) console.log('end')

When you use setTimeout , the inner code is pulled out of the current event loop to run later.当您使用setTimeout时,内部代码会从当前事件循环中拉出以便稍后运行。 That's why end is logged before the timeout .这就是在timeout之前记录end的原因。

So when you use setTimeout to return the data, the function has already ended before the code inside the timeout even starts.因此,当您使用setTimeout返回数据时,function 在超时内的代码甚至开始之前就已经结束。

If you're new to the event loop, here's a really great talk: https://youtu.be/cCOL7MC4Pl0如果您是事件循环的新手,这里有一个很棒的演讲: https://youtu.be/cCOL7MC4Pl0

returning inside setTimeout在 setTimeout 内返回

However, there's another fundamental problem here.然而,这里还有另一个根本问题。 And it's that data returned inside of the setTimeout is the return value of the setTimeout function, not your parent function.而在setTimeout内部返回的数据是setTimeout function的返回值,而不是你的父function。 Try running this, what do you think will happen?试试运行这个,你认为会发生什么?

 const foo = () => { setTimeout(() => { return 'foo timeout' }, 1000) } const bar = () => { setTimeout(() => { return 'bar timeout' }, 1000) return 'bar' } console.log(foo()) console.log(bar())

This is a result of a) the event loop mentioned above, and b) inside of the setTimeout , you're creating a new function with a new scope.这是 a) 上述事件循环和 b) 在setTimeout内部的结果,您正在使用新的 scope 创建一个新的 function。

The solution解决方案

If you really need the setTimeout at the end, use a Promise.如果最后真的需要setTimeout ,请使用 Promise。 With a Promise, you can use the resolve parameter to resolve the outer promise from within the setTimeout.使用 Promise,您可以使用resolve参数从 setTimeout 内解析外部 promise。

 const foo = () => { return new Promise((resolve) => { setTimeout(() => resolve('foo'), 1000) }) } const wrapper = async () => { const returnedValue = await foo() console.log(returnedValue) } wrapper()

Quick note速记

Since you're calling the setTimeout inside of an async function, you will likely want to move the setTimeout into it's own function.由于您在异步 function 中调用setTimeout ,因此您可能希望将 setTimeout 移动到它自己的 function 中。 Otherwise, you are returning a nested promise.否则,您将返回嵌套的 promise。

// don't do this

const foo = async () => {
  return new Promise((resolve) => resolve(true))
}

// because then the result is a promise
const result = await foo()
const trueResult = await result()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在将值插入数据库之前检查从 api 接收的数据中是否已经存在值 - How to check if value already exists in the data received from api before inserting it into db 使用 then 或 await 时,在快速路由中获取 API 数据返回未定义 - Fetching API data inside express route returns undefined when using then or await 在 API 调用完成之前快速解析路由 - Express resolving route before API call completes 如何调用POST路由函数按顺序获取API数据(JS)? - How to call POST route functions to fetch API data in order (JS)? 在第一次 api 调用返回数据后进行第二次 api 调用 - Make second api call after first api call returns data 如何让我的 Hapi 路由在返回值之前等待数据? - How can I make my Hapi route wait for data before returning a value? 程序在收到异步结果之前结束 - Program ends before async result is received 如何在触发下一个 function 之前等待 API 调用数据? - How to wait for API Call Data before next function is triggered? RecatJS:如何在将数据加载到表中之前等待 REST Api 响应 - RecatJS: How to wait for REST Api response before loading the data in a table NextJs - 节点 - API 在不发送 /api/xxx 响应的情况下解析 - NextJs - Node - API resolved without sending a response for /api/xxx
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM