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
时,内部代码被拉出当前事件循环到运行之后。这就是 end
在 timeout
.
之前记录的原因
所以当你使用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()
我不确定这里发生了什么。在加载数据之前,我在 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
时,内部代码被拉出当前事件循环到运行之后。这就是 end
在 timeout
.
所以当你使用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()