2016-03-10 4 views
0

Я создаю XML-файл, прокручивая массив, используя подчеркивание каждого. В этом цикле мне нужно вызвать внешний ресурс для извлечения значения для записи элемента XML для этого конкретного элемента в массиве.Упорядоченный JavaScript-обещание в каждом цикле

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

Я возвращаю Promise в функции, которая извлекает значение, но это явно неверно.

import Promise from 'bluebird'; 
import XMLWriter from 'xml-writer'; 
import _ from 'underscore'; 
import request from 'request'; 


class Tester { 
    writeXml() { 
    let stores = [ 
     {StoreId: 1, LocationId: 110}, 
     {StoreId: 14, LocationId: 110}, 
     {StoreId: 15, LocationId: 110}, 
    ]; 

    let xw = new XMLWriter(); 
    xw.startDocument(); 
    xw.startElement('Stores'); 

    // Loop through all the stores to write the XML file. 
    _.each(stores, (s) => { 
      xw.startElement('Store') 
      .startElement('StoreId').text(s.StoreId).endElement() 
      .startElement('LocationId').text(s.LocationId).endElement() 

      // Need to call an external resource here to get the 
      // store code, but unsure how to do this. 
      this.getStoreCode(s.LocationId, s.StoreId).then((storeCode) => { 
      xw.startElement('StoreCode').text(storeCode).endElement(); 
      }); 

      xw.endElement(); 
     }); 

    xw.endDocument(); 
    console.log(xw.toString()); 
    } 

    getStoreCode(locationId, storeId) { 
    return new Promise((resolve, reject) => { 
     let apiUrl = 'http://127.0.0.1:3000/api/v1/stores?filter' + 
     '[where][locationId]=' + locationId + 
     '&filter[where][storeId]=' + siteId + '&filter[fields][storeCode]=true'; 

     request(apiUrl, (error, response, body) => { 
     if (!error) { 
      let result = JSON.parse(body); 
      return resolve(result[0].storeCode); 
     } else { 
      return reject(error); 
     } 
     }); 
    }); 
    } 
} 

new Tester().writeXml(); 
+0

Я думаю, вам нужно сначала загрузить свой ресурс, а затем написать структуру xml. – webduvet

+0

Я согласен с webduvet. Сначала загрузите все свои ресурсы в объекты JS, а затем, как только все обещания будут решены, напишите xml. – adam0101

+0

Посмотрите на 'Promise.all'. Вы должны использовать 'map' вместо' forEach' – Bergi

ответ

2

Непрошеный, но это путь (или, что более скромно, один из способов).

writeXml(stores) { 
    let xw = new XMLWriter(); 
    xw.startDocument(); 
    xw.startElement('Stores'); 

    return Promise.map(stores, (store) => { 
    return this.getStoreCode(store.LocationId, store.StoreId).then((storeCode) => { 
     store.StoreCode = storeCode; 
     return store; 
    }); 
    }).each((storeWithStoreCode) => { 
    xw.startElement('Store'); 
    _.each(['StoreId', 'LocationId', 'StoreCode'], (prop) => { 
     xw.startElement(prop).text(storeWithStoreCode[prop]).endElement(); 
    }); 
    xw.endElement(); 
    }).then(() => { 
    xw.endDocument(); 
    return xw; 
    }); 
} 

и

writeXml([ 
    {StoreId: 1, LocationId: 110}, 
    {StoreId: 14, LocationId: 110}, 
    {StoreId: 15, LocationId: 110}, 
]).then((xw) => { 
    console.log(xw.toString()); 
}); 

В английском языке это использует Promise.map() проецировать простые store объекты в Promises для хранения объектов, которые имеют свойство StoreCode.

После этого .each() из них записывается в XML-запись в последовательности.

В конце концов вся цепочка решает сам объект записи XML, возможно, вы захотите изменить его на другой результат.

Функции, которые используют обещания, должны возвращать обещание (или вызвать какой-то обратный вызов), чтобы код вызова имел возможность узнать, когда эта функция будет выполнена.

+0

Это было очень полезно, спасибо. – duffn

+0

Можно ли опустить 'xw.endElement()' matching 'xw.startElement ('Stores')'? –

+0

@ Роамер-1888 Я не уверен. Интуитивно я бы ожидал, что 'endDocument()' неявно заканчивает все открытые элементы, но я его не тестировал (или искал). – Tomalak

Смежные вопросы