Использование конструктора Promise для преобразования каждого элемента в массив и возврата элемента обратно

1

Я использую Geocodio, это геокодирование на основе обратного вызова. У меня есть массив объектов, каждый из которых имеет объект ресторана, вложенный в него. См. Пример ниже:

{
    id: 0, title: "Half off all pizzas", 
    details:"Carry out only, all-day", 
    days: ["Monday", "Tuesday"],
    restaurant: {
        name: "Papa John's", 
        addressOne: "2937 Greenville Ave", 
        city: "Dallas", 
        state: "TX", 
        zip: 75206
    } 
}

В настоящее время я просматриваю массив объектов, чтобы передать каждый адрес ресторана в функцию геокодирования. Затем я хочу добавить свойство к этому объекту, называемому местоположением, которое будет содержать результаты геокодирования. Однако элемент возвращается до того, как результаты функции могут быть переданы в объект. Увидеть ниже:

generateCoordinates (req, res, next) {
    var newDeals = deals.map((cur, ind, arr) => {
        location = new Promise (function(resolve, reject) { 
            geocodio.get('geocode',  {q: '${cur.restaurant.addressOne}, 
                ${cur.restaurant.city}, ${cur.restaurant.state}, 
                ${cur.restaurant.zip}'}, function(err, response) {
                    if (err) {
                        reject(err)
                        throw err;
                    }
                    else {
                        var result = JSON.parse(response);
                        let obj = result.results[0].location;
                        // console.log(obj);
                        resolve(obj)
                    }
                }
            )}).then((obj) => {
                cur.location = obj;
                console.log(cur)
                return cur;
            })
        return cur;
        // console.log(newDeals)
    }) 
    res.status(200).send(newDeals)
},

Там хороший шанс, что я злоупотребляю конструктором Promise здесь. Консоль.log в.then показывает, что каждый элемент имеет правильное добавление свойства местоположения, но ответ и console.log(newDeals) показывают значение как "Promise".

Как установить свойство location для каждого элемента массива?

  • 0
    Нет, вы не пропустите его, но вы должны вернуть обещание и использовать Promise.all для возвращаемого массива.
  • 0
    geocodio.get() ли geocodio.get() Promise ? Вы могли бы избежать явной конструкции Promise, если она это сделает.
Показать ещё 1 комментарий
Теги:
arrays
es6-promise
geocoding

2 ответа

1
Лучший ответ

Да, вы не должны ничего делать в обратном вызове async, но для вызова resolve или reject. Особенно вы не должны throw !

return cur не работает точно, потому что это происходит до того, как обещание будет разрешено. Вам нужно будет вернуть обещание из обратного вызова map а затем дождаться всех обещаний в массиве, используя Promise.all. Когда это будет наконец выполнено, только тогда вы сможете отправить ответ. Также не забудьте отправить соответствующий ответ при возникновении ошибки.

generateCoordinates (req, res, next) {
    var newDeals = deals.map((cur, ind, arr) =>
        new Promise((resolve, reject) => {
            geocodio.get('geocode', {
                q: '${cur.restaurant.addressOne},
                    ${cur.restaurant.city}, ${cur.restaurant.state},
                    ${cur.restaurant.zip}'
            }, (err, response) => {
                if (err) reject(err);
                else resolve(response);
            });
        }).then(response => {
            var result = JSON.parse(response);
            let obj = result.results[0].location;
            cur.location = obj;
            console.log(cur)
            return cur;
        })
    );
    Promise.all(newDeals).then(results => {
        res.status(200).send(results);
    }, err => {
        res.status(500); // or whatever
        console.error(err);
    });
}
  • 0
    Просто к вашему сведению, ваш код не будет работать. Вам нужно вернуть обещание внутри карты, иначе вы получите массив, заполненный undefined
  • 1
    @KarimHKyler Я использовал функцию стрелки с кратким телом, которое неявно возвращает обещание. Обратите внимание на «пропущенные» скобки.
Показать ещё 1 комментарий
0

Итак, вы хотите вернуть массив значений? у вас почти есть это, но вам нужно ждать, пока обещания разрешатся. что-то вроде этого:

generateCoordinates (req, res, next) {
    var newDeals = deals.map((cur, ind, arr) => {
        return new Promise (function(resolve, reject) { 
            geocodio.get('geocode',  {q: '${cur.restaurant.addressOne}, 
            ${cur.restaurant.city}, ${cur.restaurant.state}, 
            ${cur.restaurant.zip}'}, function(err, response) {
                if (err) {
                   return reject(err);
                }
                else {
                    var result = JSON.parse(response);
                    let obj = result.results[0].location;
                    // console.log(obj);
                    resolve(obj)
                }
            }
        )}).then((obj) => {
            cur.location = obj;
            console.log(cur)
            return cur;
        });

    //newDeals is an array of promises at this point
    Promise.all(newDeals).then(results => {
      //results here is a value resolved from your promise above
      return res.status(200).send(results)
    }).catch(er r=> {
    //handle errror
    });
},

То, что я делаю, это использовать карту здесь, чтобы создать массив обещаний. Затем используйте Promise.all чтобы дождаться обещаний. все, что вы вернетесь из then блокировать внутри вашей map будет в конечном итоге, как массив в then блок Promise.all. Если вы Promise.all от каких-либо обещаний, они автоматически поймают их в Promise.all

  • 0
    Это сработало. Сначала думал, что это не работает, потому что я не заметил, что вы вернули новое обещание. Спасибо!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню