NextJS API 路由Returns 收到数据之前?

NextJS API Route Returns Before Data Received?

我不确定这里发生了什么。在加载数据之前,我在 NextJS 中设置了一个 API 路由 returns 。谁能指出这里的任何错误?

我有这个调用来自 makeRequest() 的数据的函数:

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

然后路由:/api/vendors.js

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

这是 makeRequest 函数:

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);
  }
};

我遇到的问题是 getVendors() 在 makeRequest() 完成获取数据之前返回。

看来您的问题源于您对 setTimeout 的使用。您正在尝试从 setTimeout 调用中 return 数据,但由于一些原因,这将不起作用。因此,在这个答案中,我将讨论为什么我认为它不起作用以及为您提供一个潜在的解决方案。

setTimeout 和事件循环

看看这段代码,您认为会发生什么?

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

当你使用setTimeout时,内部代码被拉出当前事件循环到运行之后。这就是 endtimeout.

之前记录的原因

所以当你使用setTimeout到return数据时,函数在超时里面的代码开始之前就已经结束了。

如果您是事件循环的新手,这里有一个非常棒的演讲:https://youtu.be/cCOL7MC4Pl0

return在 setTimeout

里面

然而,这里还有另一个基本问题。 setTimeout 内部的数据 returned 是 setTimeout 函数的 return 值,而不是您的父函数。尝试 运行ning 这个,你认为会发生什么?

const foo = () => {
  setTimeout(() => {
    return 'foo timeout'
  }, 1000)
}

const bar = () => {
  setTimeout(() => {
    return 'bar timeout'
  }, 1000)
  return 'bar'
}

console.log(foo())
console.log(bar())

这是 a) 上述事件循环和 b) 在 setTimeout 内部的结果,您正在创建具有新作用域的新函数。

解决方法

如果您真的需要最后的 setTimeout,请使用 Promise。使用 Promise,您可以使用 resolve 参数从 setTimeout 中解决外部承诺。

const foo = () => {
  return new Promise((resolve) => {
    setTimeout(() => resolve('foo'), 1000)
  })
}

const wrapper = async () => {
  const returnedValue = await foo()
  console.log(returnedValue)
}

wrapper()

速记

由于您是在异步函数内部调用 setTimeout,您可能希望将 setTimeout 移动到它自己的函数中。否则,您将 return 嵌套承诺。

// 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()