Использование обещаний в экспрессе - PullRequest
0 голосов
/ 11 марта 2019

Мне нужно приложение, в котором пользователь вводит адрес в виде строки запроса, а затем получает погоду для этого местоположения в виде объекта json. В части поиска погоды я использую обещания, чтобы получить широту и долготу для адреса, а затем погоду. Есть также варианты для указания языка и единиц измерения.

function getWeather(encodedAddress, units, language) {
    let geoKey = 'XXXXXXXXXXXXXXXXXXXXXXXXXXX';
    let geocodeURL = `http://www.mapquestapi.com/geocoding/v1/address?key=${geoKey}&location=${encodedAddress}`;

    return axios.get(geocodeURL).then(({data}) => {
        if (((data.results[0].locations[0].geocodeQualityCode.substring(2)).match(/X/g) || []).length > 1) {
            throw new Error('Unable to find that address')
        }
        const locationInfo = data.results[0].locations[0];
        const lat = locationInfo.latLng.lat;
        const lng = locationInfo.latLng.lng;

        console.log('Here\'s the weather for: ', locationInfo.street, locationInfo.adminArea5,
                                locationInfo.adminArea4, locationInfo.adminArea1, 
                                locationInfo.postalCode);
        
        const weatherKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';
        
        units = units ? `units=${units}` : 'auto';
        language = language ? `lang=${language}` :  'lang=en';
        
        const weatherURL = `https://api.darksky.net/forecast/${weatherKey}/${lat},${lng}?${units}&${language}`;
        return axios.get(weatherURL);

    }).then(({data}) => {
        const tempInfo = data.currently;
        const temp = tempInfo.temperature;
        const apparentTemp = tempInfo.apparentTemperature;
        const summary = tempInfo.summary;

        console.log(`It's currently ${temp} degrees and feels like ${apparentTemp} degrees. \nThe local summary is: ${summary}.`);

        return data.currently;
        
    }).catch(error => {
        if (error.code === 'ENOTFOUND') {
            throw new Error('Could not connect to MapRequest server');
        } else {
            throw new Error(error.message);
        }
    });
};

В моем app.js у меня есть

app.get('/weather', (req, res, next) => {
    if (!req.query.address) {
        return res.send({
            error: 'You must provide an address!'
        })
    }

    forecast.getWeather(req.query.address).then(function(data) {
         res.send(data);
    });
    next();
});

Я получаю Cannot read property then of undefined ошибку в браузере. Я думаю, это потому, что когда ответ отправлен, обещание не разрешается. Приложение app.get основано на том, что находится в экспресс-документации, поэтому я думаю, что это может быть связано с моей функцией getWeather. Как я могу дождаться выполнения обещания, а затем выполнить все действия?

Ответы [ 2 ]

1 голос
/ 11 марта 2019

Вы вызываете экспресс-обратный вызов сразу после запроса данных, здесь:

forecast.getWeather(req.query.address).then(function(data) {
    res.send(data);
});
next();

Попробуйте это:

forecast.getWeather(req.query.address).then(function(data) {
    res.send(data);
    next();
});

Кроме того, я бы порекомендовал catch - сообщить об ошибке в вашем маршрутизаторе Express и передать ее в обработчик ошибок Express, чтобы HTTP-запрос не работал должным образом, а не просто зависал:

forecast.getWeather(req.query.address).then(function(data) {
    res.send(data);
    next();
}).catch(next);

Последняя строка является сокращением для }).catch(err => next(err));.

0 голосов
/ 11 марта 2019

Вы можете использовать Promise или Bluebird npm для пакета обещаний.

Попробуйте это.

const Promise = require('promise')

function getWeather(encodedAddress, units, language) {
    return new Promise((resolve, reject) => {
        let geoKey = 'XXXXXXXXXXXXXXXXXXXXXXXXXXX';
        let geocodeURL = `http://www.mapquestapi.com/geocoding/v1/address?key=${geoKey}&location=${encodedAddress}`;

    axios.get(geocodeURL).then(({ data }) => {
        if (((data.results[0].locations[0].geocodeQualityCode.substring(2)).match(/X/g) || []).length > 1) {
            throw new Error('Unable to find that address')
        }
        const locationInfo = data.results[0].locations[0];
        const lat = locationInfo.latLng.lat;
        const lng = locationInfo.latLng.lng;

        console.log('Here\'s the weather for: ', locationInfo.street, locationInfo.adminArea5,
            locationInfo.adminArea4, locationInfo.adminArea1,
            locationInfo.postalCode);

        const weatherKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';

        units = units ? `units=${units}` : 'auto';
        language = language ? `lang=${language}` : 'lang=en';

        const weatherURL = `https://api.darksky.net/forecast/${weatherKey}/${lat},${lng}?${units}&${language}`;
        axios.get(weatherURL).then(resolve).catch(reject);

    }).then(({ data }) => {
        const tempInfo = data.currently;
        const temp = tempInfo.temperature;
        const apparentTemp = tempInfo.apparentTemperature;
        const summary = tempInfo.summary;

        console.log(`It's currently ${temp} degrees and feels like ${apparentTemp} degrees. \nThe local summary is: ${summary}.`);

        resolve(data.currently);

    }).catch(error => {
        if (error.code === 'ENOTFOUND') {
            reject(new Error('Could not connect to MapRequest server'));
        } else {
            reject(Error(error.message));
        }
    });
});
};
...