【问题标题】:Async/Await not working for VueX getter but works for logAsync/Await 不适用于 VueX getter 但适用于日志
【发布时间】:2019-04-12 16:49:45
【问题描述】:

我有一个带有 userIDs 的 convos 对象,我需要遍历该对象,并且在循环内,我需要调用 Firebase 以获取相应的 userName然后返回一个包含 convos、userNames 和 userIDs 的对象。

我尝试过使用 async/await,我从 console.log 得到的结果是正确的,但之后我的 return 语句是未定义的。为什么会这样?他们正在接收相同的对象。

store.js getter sn-p

getConvosObj: state => {
  var convoObj = {};
  var userConvos = state.userProfile.convos;
  async function asyncFunction() {
    for (const key in userConvos) {
      if (userConvos.hasOwnProperty(key)) {
        const userID = userConvos[key];
        var userName;
        await fire.database().ref('/users/' + userID + '/userName').once('value', async (snapshot) => {
          userName = await snapshot.val();
          convoObj[key] = {userName, userID}
        })
      }
    }
    console.log(convoObj);   //result: correct object
    return convoObj;         //result: undefined
  }
  asyncFunction();
}

【问题讨论】:

  • 你怎么知道你的函数返回undefined
  • 我假设你认为getConvosObj 会返回convoObj?因为它不返回任何东西。
  • 按照设计,getter 并不意味着是异步的。相反,它们应该返回某个存储状态,并在状态更改时进行响应式更新。事实上,上面的代码示例很难预测,这只是证明了这个概念。这种方法也存在性能缺陷。请尝试坚持最初的想法:调用动作 -> 用突变改变状态 -> 用吸气剂返回状态。这种方式流程清晰且可调试。
  • 是的,我试图使用getConvosObj 来返回convoObj。我对 Vue 还很陌生,所以我不记得我不应该在 getter 中做异步的东西。我已经按照下面 sosmii 建议的方式对其进行了重组,现在可以使用了。谢谢大家!

标签: javascript firebase vue.js async-await vuex


【解决方案1】:

为什么会这样?

因为你同步调用了异步函数。
让您的代码更简单。

getConvosObj: state => {
    async function asyncFunction() {
        // ...
    }

    asyncFunction();
}

此时,您的getConvosObj() 将返回nothing,因为getConvosObj()asyncFunction() 结束之前结束。
您需要等到您的asyncFunction() 结束,然后您的代码应该是这样的:

getConvosObj: async state => { // <- changed here
  async function asyncFunction() {
    // ...
  }

  await asyncFunction(); // <- changed here too
}

但是你不应该这样做,因为 getter 的设计并不意味着异步。
这可能有效,但您应该尝试不同的方法。

那你该怎么办?

在使用 getter 之前使用操作

这是一种基本方法。

异步函数应该在动作中。
所以你的商店应该是这样的:

export default () => 
  new Vuex.Store({
    state: {
      convoObj: null
    },
    mutations: {
      updateConvoObj(state, payload) {
        state.convoObj = payload;
      }
    },
    actions: {
      async fetchAndUpdateConvoObj({ state, commit }) {
        const fetchUserData = async userId => {
          const snapShot = await fire.database().ref('/users/' + userID + '/userName').once('value');
          const userName = snapShot.val();

          return {
            userName: userName,
            userID: userId
          }
        }

        const userConvos = state.userProfile.convos;

        let convoObj = {};
        for (const key in userConvos) {
          if (userConvos.hasOwnProperty(key)) {
            const userId = userConvos[key];
            const result = await fetchUserData(userId);

            convoObj[key] = {
              userName: result.userName,
              userId: result.userId
            }
          }
        }

        commit('updateConvoObj', convoObj);
      }
    }
  });

然后在您的sample.vue 中使用getter 之前调用您的操作:

await this.$store.dispatch('fetchAndUpdateConvoObj');
convoObj = this.$store.getters('getConvoObj');

等待数据库并更新存储,然后获取其状态。
没有意义?

使用 vuexfire 将您的商店直接连接到实时数据库

另一种方法是这样。

使用 vuexfire,那么 store 的状态始终是实时数据库的最新状态,因此您可以在不调用操作的情况下调用 getter。
我厌倦了重构/编写代码,所以如果你想使用那个插件,请谷歌一些示例:)

我对原始代码进行了很多重构,所以应该有一些错字或错误。
如果你找到了,请修改。

【讨论】:

  • but you should not do like this, because getters are not meant to be asynchronous by design.投一票
猜你喜欢
  • 2018-03-24
  • 1970-01-01
  • 2018-08-23
  • 2019-10-24
  • 2018-07-10
  • 2021-06-18
  • 2019-05-30
  • 2021-05-10
  • 1970-01-01
相关资源
最近更新 更多