【问题标题】:Object literal (hash) with Promise.all带有 Promise.all 的对象字面量(哈希)
【发布时间】:2016-06-20 11:04:39
【问题描述】:

我有一种情况,使用 Promise.allPromise.all({}) 代替更标准的 Promise.all([]) 会非常方便。

但这似乎不起作用

Promise.all({a:1,b:2}).then(function(val){
   console.log('val:',val);
});

当然是这样

Promise.all([1,2,3]).then(function(val){
   console.log('val:',val);
});

(我希望 Promise.all 映射 Object 文字的值,但保持键不变。)

the MDN docs for Promise 似乎表明 Promise all 将适用于任何可迭代对象。据我所知,对象文字 {} 是可迭代的。那我错过了什么?

【问题讨论】:

  • 不,{} 不是可迭代的。
  • 从这些文档中不清楚 {} 是否是可迭代的,但它似乎是 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • @AlexMills 不知道你为什么认为它不清楚。您链接的 MDN 文章解释了“某些内置类型是具有默认迭代行为的内置可迭代对象,例如 Array 或 Map,而其他类型(例如 Object)则不是”。跨度>
  • 如果您想知道{} 是否是可迭代的,请尝试在控制台中输入以下任何内容。 (1)[...{}] (2)for (i of {}) {}.
  • 为什么它真的很方便?你没有解释你想要做什么。您可以尝试做很多可能的事情,但是对于将对象塞入 Promise.all 中没有任何一个真正有意义,其目的是合并 Promise,这看起来不像您要尝试的那样做。

标签: javascript node.js ecmascript-6 es6-promise


【解决方案1】:

这是另一个异步/等待 ES6 解决方案:

async function allOf(hash = {}) {
  const promises = Object.keys(hash).map(async key => ({[key]: await hash[key]}));
  const resolved = await Promise.all(promises);
  return resolved.reduce((hash, part) => ({...hash, ...part}), {});
}

这会将键转换为产生单个元素哈希的承诺。然后最后我们将数组中的所有散列组合成一个散列。您甚至可以将其压缩为单行,以牺牲可读性为代价。

async function allOfOneLiner(hash = {}) {
  return (await Promise.all(Object.keys(hash).map(async k => ({[k]: await hash[k]})))).reduce((h, p) => ({...h, ...p}), {});
}

【讨论】:

  • 这个真的很优雅,很好看。
【解决方案2】:

如果您查看 mdn documentation 中的那些,对象没有迭代器符号。

您可以做的是使用工具函数创建一个可迭代的对象,然后再使用它。

reference to objectEntries source,但是 nodejs 没有实现 Reflect,所以为了在 node 中使用它,我只是将它改为使用 Object.keys()

function objectEntries(obj) {
    let index = 0;

    // In ES6, you can use strings or symbols as property keys,
    // Reflect.ownKeys() retrieves both
    let propKeys = Object.keys(obj);

    return {
        [Symbol.iterator]() {
            return this;
        },
        next() {
            if (index < propKeys.length) {
                let key = propKeys[index];
                index++;
                return { value: [key, obj[key]] };
            } else {
                return { done: true };
            }
        }
    };
}

【讨论】:

    【解决方案3】:

    使用Object.values。在 Firefox Nightly 中工作:

    Promise.all(Object.values({a:1,b:2}))
    .then(vals => console.log('vals: ' + vals)) // vals: 1,2
    .catch(e => console.log(e));
    
    var console = { log: msg => div.innerHTML += msg + "<br>" };
    &lt;div id="div"&gt;&lt;/div&gt;

    然后,要将结果放回对象中,我们可以创建一个Promise.allParams 函数:

    Promise.allParams = o => 
      Promise.all(Object.values(o)).then(promises =>
        Object.keys(o).reduce((o2, key, i) => (o2[key] = promises[i], o2), {}));
    
    // Demo:
    
    Promise.allParams({a:1,b:2}).then(function(val){
       console.log('val: ' + JSON.stringify(val)); // val: {"a":1,"b":2}
    });
    
    var console = { log: msg => div.innerHTML += msg + "<br>" };
    &lt;div id="div"&gt;&lt;/div&gt;

    【讨论】:

    • 这个解决方案的问题是结果数组中元素的顺序取决于Object.values返回的数组中值的顺序,这可能不是您想要依赖的.
    • @torazaburo 当然,但这个问题是问题所固有的。
    • 不是。您应该像 RSVP 一样返回承诺结果的哈希值。
    • @torazaburo 啊,错过了。已更新。
    • 注意Object.values 只是一个提案,但它还没有出现在正式的 ECMAScript 草案中。
    【解决方案4】:
    Syntax
    Promise.all(iterable);
    Parameters
    

    可迭代

    一个可迭代的对象,例如一个数组。请参阅可迭代。

    【讨论】:

    【解决方案5】:

    这个函数可以解决问题:

    Promise.allAssoc = function(object){
        var values = [], keys = [];
        for(var key in object){
            values.push(object[key]);
            keys.push(key);
        }
        return Promise.all(values).then(function(results){
            var out = {};
            for(var i=0; i<results.length; i++) out[keys[i]] = results[i];
            return out;
        });
    };
    

    【讨论】:

      【解决方案6】:

      默认情况下,并非所有对象都是可迭代的。您可以通过定义 @@iterator 方法使对象可迭代。 @@iteratorWell-Known Symbol,可用作 Symbol.iterator

      • 规范名称
        @@迭代器
      • [[描述]]
        "Symbol.iterator"
      • 价值和目的
        返回对象的默认迭代器的方法。由 for-of 语句的语义调用。

      例如,这将使所有对象都可迭代(可能不是一个好主意):

      Object.prototype[Symbol.iterator] = function*() {
        for(let key of Object.keys(this))
          yield this[key];
      };
      

      然后你就可以使用了

      Promise.all({a:1,b:2}).then(function(val){
         console.log('val:', val); // [ 1, 2 ]
      });
      

      【讨论】:

      • 有没有办法轻松修改它,以便“then”回调向我们传递一个对象/散列,其中原始键与值匹配,而不是数组?
      • @AlexMills 我不明白。你想用一个对象调用Promise.all,并得到同一个对象吗?有什么意义?
      • :) 我想使用 Promise.all 并将 Promise 中的值映射到 Promise 结果,同时保持键不变。所以 {a: Promise} 变成 {a:'some-other-value'}
      • @AlexMills 这有道理,但我认为你不能。不过,我对 Promises 了解不多。
      • 是的,我试过了,但我认为不改变 Promise.all 的内部实现是不可能的
      【解决方案7】:

      使用 Babel/ES2015,您可以使用 Object.keys 和 map 来获取如下值:

      const obj = {a:1,b:2};                                                                                                                               
      const vals = Object.keys(obj).map(k=>obj[k]);                                                                                                        
      Promise.all(vals).then( vals => { console.log('vals', vals) });                         
      

      【讨论】:

      • 我怀疑 OP 更愿意返回一个带有承诺的哈希作为键的值。
      【解决方案8】:

      ES6 方式

      Promise.hashProperties = async function(object) {
          const keys = [];
          const values = [];
      
          for (const key in object) {
              keys.push(key);
              values.push(object[key]);
          }
      
          const results = await Promise.all(values);
      
          for (var i=0; i<results.length; i++)
              object[keys[i]] = results[i];
      
          return object;
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-08-15
        • 1970-01-01
        • 2013-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-19
        相关资源
        最近更新 更多