Как заказать порядок возвращаемых вызовов API с генераторами? - PullRequest
1 голос
/ 16 июня 2019

Я практикую некоторые более продвинутые техники Javascript и натолкнулся на генераторы и итераторы как на то, что я хотел бы изучить.Я знаю, что я делаю это неправильно, но я не совсем уверен, как это сделать.

Идея моей маленькой программы заключается в следующем: я хочу сделать API-вызовы API OpenWeather для четырех(или больше, но я тестирую с четырьмя) городами.Города хранятся в массиве, и один за другим город добавляется к 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) передает указанный город первомуyield
  • Третий .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 И я не уверен, где я ошибаюсь здесь с моимлогика.Как мне реорганизовать это, чтобы позволить мне ждать конкретных обещаний, если я не могу по отдельности передать известные значения?Я знаю, что должен быть способ, но я что-то упускаю.

Заранее спасибо.

1 Ответ

1 голос
/ 16 июня 2019

Я не понимаю, какую выгоду вы надеетесь получить от использования генератора, но причина, по которой вы получаете эту ошибку, заключается в том, что вы делаете один ко многим .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.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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...