Dar*_*ley 3 event-loop settimeout async-await es6-promise next.js
我不确定这里发生了什么事。我在 NextJS 中设置了一个 API 路由,该路由在数据加载之前返回。有人可以指出这里有任何错误吗?
我有一个调用 makeRequest() 中的数据的函数:
export async function getVendors() {
const vendors = await makeRequest(`Vendor.json`);
console.log({ vendors });
return vendors;
}
Run Code Online (Sandbox Code Playgroud)
然后路由:/api/vendors.js
export default async (req, res) => {
const response = await getVendors();
return res.json(response);
};
Run Code Online (Sandbox Code Playgroud)
这是 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);
}
};
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是 getVendors() 在 makeRequest() 完成获取数据之前返回。
看来您的问题源于您对 的使用setTimeout。您正在尝试从内部返回数据setTimeout,但由于某些原因,这不起作用。因此,在这个答案中,我将回顾为什么我认为它不适合您以及潜在的解决方案。
看看这段代码,你认为会发生什么?
console.log('start')
setTimeout(() => console.log('timeout'), 1000)
console.log('end')Run Code Online (Sandbox Code Playgroud)
当您使用 时setTimeout,内部代码将从当前事件循环中拉出以便稍后运行。这就是为什么end在之前记录timeout原因。
所以当你使用setTimeout返回数据时,在超时内的代码开始之前,函数就已经结束了。
如果您是事件循环的新手,这里有一个非常精彩的演讲: https: //youtu.be/cCOL7MC4Pl0
然而,这里还有另一个根本问题。内部返回的数据setTimeout是函数的返回值setTimeout,而不是父函数的返回值。尝试运行这个,你认为会发生什么?
const foo = () => {
setTimeout(() => {
return 'foo timeout'
}, 1000)
}
const bar = () => {
setTimeout(() => {
return 'bar timeout'
}, 1000)
return 'bar'
}
console.log(foo())
console.log(bar())Run Code Online (Sandbox Code Playgroud)
这是 a) 上面提到的事件循环和 b) 内部的结果setTimeout,您正在创建一个具有新作用域的新函数。
setTimeout如果最后确实需要,请使用 Promise。通过 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()Run Code Online (Sandbox Code Playgroud)
由于您正在调用setTimeout异步函数的内部,因此您可能希望将 setTimeout 移动到它自己的函数中。否则,您将返回一个嵌套的承诺。
// 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()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9248 次 |
| 最近记录: |