javascript - 将 promise 的 future 值保存在变量中

标签 javascript node.js mongoose promise

我有一个数据库需要最近消息的列表。每条消息都是一个对象,并作为这些消息对象的数组存储在 chatListNew 中。

每个消息对象都有一个属性“from”,它是发布该消息的用户的 ID。我想要做的是循环遍历这个数组并将“From”用户的实际配置文件信息附加到对象本身中。这样,当前端收到信息时,它就可以访问相应消息的 fromProfile 属性中的一条特定消息的发件人配置文件。

我考虑过循环遍历每个消息并为每个消息执行 Promise.All,但是,如果只有少数用户发布了数百条消息,那么这将非常昂贵。 只为每个用户运行一次 mongoose 查询会更有意义。所以我发明了一个缓存系统。

但是,我对如何在数组元素内存储 future 值的 promise 感到困惑。我认为将“fromProfile”设置为之前调用的 promise 会神奇地保持这个 promise ,直到该值得到解析。因此我使用 Promise.all 来确保所有的 Promise 都已完成,然后由结果返回,但我存储在数组中的 Promise 并不是我希望的值。

这是我的代码:

//chatListNew = an array of objects, each object is a message that has a "from" property indicating the person-who-sent-the-message's user ID

let cacheProfilesPromises = []; // this will my basic array of the promises called in the upcoming foreach loop, made for Promise.all
let cacheProfilesKey = {}; // this will be a Key => Value pair, where the key is the message's "From" Id, and the value is the promise retrieving that profile
let cacheProfileIDs = []; // this another Key => Value pair, which basically stores to see if a certain "From" Id has already been called, so that we can not call another expensive mongoose query


chatListNew.forEach((message, index) => {
    if(!cacheProfileIDs[message.from]) { // test to see if this user has already been iterated, if not
        let thisSearch = User.findOne({_id : message.from}).select('name nickname phone avatar').exec().then(results => {return results}).catch(err => { console.log(err); return '???' ; }); // Profile retrieving promise
        cacheProfilesKey[message.from] = thisSearch;
        cacheProfilesPromises.push(thisSearch); // creating the Array of promises
        cacheProfileIDs[message.from] = true;
    }

    chatListNew[index]["fromProfile"] = cacheProfilesKey[message.from]; // Attaching this promise (hoping it will become a value once promise is resolved) to the new property "fromProfile"
});

Promise.all(cacheProfilesPromises).then(_=>{ // Are all promises done?
    console.log('Chat List New: ', chatListNew);
    res.send(chatListNew);
});

这是我的控制台输出:

Chat List New:  [ { _id: '5b76337ceccfa2bdb7ff35b5',
updatedAt: '2018-08-18T19:50:53.105Z',
createdAt: '2018-08-18T19:50:53.105Z',
from: '5b74c1691d21ce5d9a7ba755',
conversation: '5b761cf1eccfa2bdb7ff2b8a',
type: 'msg',
content: 'Hey everyone!',
fromProfile:
 Promise { emitter: [EventEmitter], emitted: [Object], ended: true } },
{ _id: '5b78712deccfa2bdb7009d1d',
updatedAt: '2018-08-18T19:41:29.763Z',
createdAt: '2018-08-18T19:41:29.763Z',
from: '5b74c1691d21ce5d9a7ba755',
conversation: '5b761cf1eccfa2bdb7ff2b8a',
type: 'msg',
content: 'Yo!',
fromProfile:
 Promise { emitter: [EventEmitter], emitted: [Object], ended: true } } ]

而我希望得到类似的东西:

Chat List New:  [ { _id: '5b76337ceccfa2bdb7ff35b5',
updatedAt: '2018-08-18T19:50:53.105Z',
createdAt: '2018-08-18T19:50:53.105Z',
from: '5b74c1691d21ce5d9a7ba755',
conversation: '5b761cf1eccfa2bdb7ff2b8a',
type: 'msg',
content: 'Hey everyone!',
fromProfile:
 Promise {name: xxx, nickname: abc... etc} },
{ _id: '5b78712deccfa2bdb7009d1d',
updatedAt: '2018-08-18T19:41:29.763Z',
createdAt: '2018-08-18T19:41:29.763Z',
from: '5b74c1691d21ce5d9a7ba755',
conversation: '5b761cf1eccfa2bdb7ff2b8a',
type: 'msg',
content: 'Yo!',
fromProfile:
 {name: xxx, nickname: abc... etc} } ]

谢谢大家!对实现这一目标的其他方式持开放态度:) 皮特

最佳答案

当将Promise 分配给变量时,该变量始终Promise,除非重新分配该变量。您需要从 Promise.all 调用中获取 Promises结果

仅仅返回其参数的 .then 也是没有意义的,就像你的 .then(results => {return results}) - 你可以保留它完全关闭,它不会执行任何操作。

构造 Promise 数组,并构造一个 from 属性数组,以便每个 Promise 的 from 对应于另一个数组中同一索引处的项目。这样,一旦 Promise.all 完成,您就可以将解析值数组转换为由 from 索引的对象,之后您可以迭代 chatListNew 并将 resolved 值分配给每条消息的 fromProfile 属性:

const cacheProfilesPromises = [];
const messagesFrom = [];

chatListNew.forEach((message, index) => {
  const { from } = message;
  if(messagesFrom.includes(from)) return;
  messagesFrom.push(from);
  const thisSearch = User.findOne({_id : from})
    .select('name nickname phone avatar')
    .exec()
    .catch(err => { console.log(err); return '???' ; });
  cacheProfilesPromises.push(thisSearch);
});

Promise.all(cacheProfilesPromises)
  .then((newInfoArr) => {
    // Transform the array of Promises into an object indexed by `from`:
    const newInfoByFrom = newInfoArr.reduce((a, newInfo, i) => {
      a[messagesFrom[i]] = newInfo;
      return a;
    }, {});

    // Iterate over `chatListNew` and assign the *resolved* values:
    chatListNew.forEach((message) => {
      message.fromProfile = newInfoByFrom[message.from];
    });
  });

关于javascript - 将 promise 的 future 值保存在变量中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52107693/

相关文章:

javascript - 在WebView中执行JS脚本

javascript - 声云 API : how to use SoundCloud song w/o the embed player?

javascript - 模拟依赖的构造函数 Jest

node.js - 在 Mongoose 中更新嵌套对象

javascript - 使用 Node.JS Mongoose 查找文档并将值插入到 MongoDB 中的数组中

javascript - 从简单字符串获取 HTML 标签并设置其格式

javascript - 检查一个 div 是否有子元素 - Jquery

node.js - Mongoose 协会

node.js - Jest 模拟模块

node.js - 仅当 ref 不为空时才尝试填充 Mongoose - 不起作用