【问题标题】:How to order the order of returned API calls with generators?如何使用生成器订购返回的 API 调用的顺序?
【发布时间】:2023-03-24 14:34:01
【问题描述】:

我正在练习一些更高级的 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()'d 的响应对象。

这是我的测试器生成器代码:

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 我不确定我的逻辑哪里出了问题。如果我不能单独传递已知值,我该如何重构它以允许我等待特定的承诺?我知道必须有办法,但我错过了一些东西。

提前致谢。

【问题讨论】:

    标签: javascript asynchronous generator


    【解决方案1】:

    我不明白你希望从这里使用生成器获得什么好处,但你得到这个错误的原因是你在做一对多 .next()'s

    第一个generator.next() 运行fetchWeather 直到第一个yield,也就是const appendedURL = url + (yield); 末尾的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));
    

    正如 cmets 中提到的,我这样做的通常方法是将城市映射到 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))
    

    【讨论】:

    • 公平地说,我手头上并没有一个很好的生成器用例,所以这背后的想法是更多地了解如何最好地订购 Promise。我的想法是我希望按照我发送它们的确切顺序查看我的回复,即使第二个或第三个先出现。
    • 为此,我只需将城市映射到一系列承诺,然后执行 promise.all。你想要一个看起来像什么的例子吗?
    • 我很乐意看到它,因为这是我完全不熟悉的范式,但我不得不问,是什么让将承诺映射到城市并立即解决所有这些问题而不是一一发送电话?这只是Promise.all()的本机行为吗?
    • 我在其中添加了一个示例。它不是按顺序进行的。它同时启动所有提取。每个 fetch 都有自己的 Promise,promise.all 创建一个 Promise,一旦所有单独的 Promise 解决,该 Promise 就会解决。外部 promise 使用一个数组解析,其中包含内部 promise 解析的所有内容(按照它们传递给 promise.all 的顺序,而不是它们解析的顺序)
    • 第一个 next() 从生成器顶部运行到第一个产量。第二个next() 从第一个收益运行到第二个收益。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    相关资源
    最近更新 更多