每个循环中的有序 JavaScript Promise

Posted

技术标签:

【中文标题】每个循环中的有序 JavaScript Promise【英文标题】:Ordered JavaScript Promise in each loop 【发布时间】:2016-06-25 12:04:05 【问题描述】:

我正在创建一个 XML 文件,同时使用下划线遍历一个数组。在那个循环中,我需要调用一个外部资源来检索一个值,以便为数组中的这个特定项目写入一个 XML 元素。

我很困惑如何从外部资源中检索值,同时保持循环的顺序,以便将值包含在数组中的正确项目中。

我在检索值的函数中返回了一个 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();

【问题讨论】:

我猜,你需要先加载你的资源,然后再写xml结构 我同意 webduvet。首先将所有资源加载到 JS 对象中,然后,一旦解决了所有承诺,就编写 xml。 看看Promise.all。你应该使用map 而不是forEach 【参考方案1】:

未经测试,但这是可行的方法(或者,更谦虚地说,是一种可行的方法)。

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 对象投影到具有StoreCode 属性的存储对象的Promise 中。

之后,.each() 将依次写入 XML 写入器。

最后整个链解析为 XML writer 对象本身,您可能希望将其更改为不同的结果。

使用 Promise 的函数应该返回一个 Promise(或调用某种回调),以便调用代码有机会知道该函数何时完成。

【讨论】:

是否允许省略匹配xw.startElement('Stores')xw.endElement() @Roamer-1888 我不确定。直觉上我本以为 endDocument() 会隐式结束所有打开的元素,但我还没有测试过(或查过)。 @duffn 不要忘记error management,在适当的地方。不定义错误行为并不理想。 @Tomalak,here 的例子表明了这一点。顺便说一句,干得好。

以上是关于每个循环中的有序 JavaScript Promise的主要内容,如果未能解决你的问题,请参考以下文章

聊一聊浏览器事件循环与前端性能

JavaScript 精粹 基础 进阶数组

[万字详解]JavaScript 中的异步模式及 Promise 使用

通过 PHP 循环动态添加 <img> 标记,通过在每个循环上调用 JavaScript 函数

Javascript中的For循环

JavaScript中的数组