如何使用生成器订购返回的API调用的顺序?

时间:2019-06-16 04:34:30

标签: javascript asynchronous generator

我正在练习一些更高级的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而且我不确定我的逻辑在哪里出问题了。如果无法单独传递已知值,该如何重构它以允许我等待特定的诺言?我知道一定有办法,但是我缺少了一些东西。

谢谢。

1 个答案:

答案 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))