我正在练习一些更高级的Javascript技术,并遇到了一些生成器和迭代器,这是我想研究的东西。我知道我做错了,但是我不确定如何去做。
我的小程序的想法是这样的:我想对四个(或更多,但我正在对四个)城市进行OpenWeather API的API调用。城市被存储在一个数组中,并一个接一个地存储,城市被附加到URL并发送获取请求。每个响应都附加到一个数组,并将该数组发送到客户端。 这是我的原始代码:
// node/express setup here
const cities = ["London%2Cuk", "New York%2Cus", "Johannesburg%2Cza", 'Kingston%2Cjm']
const url = process.env.URL_BASE;
const headers = {
"X-RapidAPI-Host": process.env.HOST,
"X-RapidAPI-Key": process.env.API_KEY
}
const requestInit = { method: 'GET',
headers: headers
};
const fetchWeather = (ep) => {
const appendedURL = url + ep;
return fetch(appendedURL, requestInit)
.then(r => r.json());
}
app.get('/', (req, res, err) => {
const data = []
Promise.all(
cities.map( async (city) => {
await fetchWeather(city)
.then(returns => {
data.push(returns)
})
})
)
.then(() => {
res.send(data)
return data;
})
.catch(err => console.log(err))
})
对吗?牢固,可以。但是现在我在如何订购它上了。我认为这样做的方式是将await fetchWeather(city)
切换为yield fetchWeather(city)
并拥有一个生成器管理器,该生成器管理器将继续调用next(city)
直到数组完成为止,但是在解决这个问题时我遇到了问题淘汰模式。我将api调用重构为生成器,并正在测试生成器管理功能。
根据我的理解,我的范例是:
.next()
开始迭代.next(args)
将指定的城市传递给第一个产量.next()
发送产生的获取请求,并且(理想情况下)应返回可以.then()
的响应对象。 这是我的测试仪生成器代码:
function *fetchWeather() {
for (let i = 0; i < cities.length; i++){
const appendedURL = url + (yield);
yield fetch(appendedURL, requestInit)
.then(r => {
return r.json()
});
}
}
const generatorManager = (generator) =>{
if (!generator) {
generator = fetchWeather();
}
generator.next()
generator.next(cities[i])
generator.next().value.then( e =>
console.log(e));
}
我遇到了错误:TypeError: Cannot read property 'then' of undefined
而且我不确定我的逻辑在哪里出问题了。如果无法单独传递已知值,该如何重构它以允许我等待特定的诺言?我知道一定有办法,但是我缺少了一些东西。
谢谢。
答案 0 :(得分:1)
我不明白您希望从此处使用生成器获得什么好处,但是出现此错误的原因是您正在做一对多的.next()
第一个generator.next()
运行fetchWeather直到第一个收益(即const appendedURL = url + (yield);
末尾的收益)。在这种情况下,调用generator.next()
的返回值为{ value: undefined, done: false }
此后,generator.next(cities[i])
恢复fetchWeather,其中cities[i]
是先前收益的结果。生成器继续运行,调用fetch
,然后在该承诺上调用.then
,然后产生结果的承诺。因此,generatorManager通过执行generator.next(cities[i])
看到的返回值为{ value: /* a promise object */, done: false }
。
因此,要纠正该错误,您需要减少对generator.next的调用次数。
generator.next()
generator.next(cities[i]).value.then(e =>
console.log(e));
正如评论中提到的,我通常这样做的方法是将城市映射到Promise,然后再做Promise.all。例如:
Promise.all(
cities.map((city) => fetchWeather(city)) // note, this is the original fetch weather, not the generator
).then((data) => {
res.send(data);
return data;
})
.catch(err => console.log(err))