异步/等待不适用于VueX getter但适用于日志

时间:2018-11-09 05:21:16

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

我有一个带有 userIDs 的convos对象,需要循环浏览,在循环内部,我需要调用Firebase以获得相应的 userName 然后返回带有convos,userName和userID的对象。

我尝试使用async / await,并且从console.log获得的结果是正确的,但是此后直接返回的语句未定义。为什么会这样呢?他们正在接收相同的对象。

store.js 吸气剂片段

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();
}

1 个答案:

答案 0 :(得分:-1)

为什么会这样?

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

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

    asyncFunction();
}

在这一点上,您的getConvosObj()将不会返回任何内容,因为getConvosObj()asyncFunction()结束之前结束。
您需要等待asyncFunction()结束,然后您的代码应如下所示:

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

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

但是您不应该这样,因为吸气剂并不是设计上异步的。
这可能有效,但是您应该尝试其他方法。

那你该怎么办?

在使用吸气剂之前先使用动作

这是一种基本方法。

异步功能应该起作用。
所以您的商店应该是这样的:

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,那么存储的状态始终是实时数据库的最新状态,因此您可以调用getter而不调用操作。
我很累要重构/编写代码,所以如果您想使用该插件,请向Google索取一些示例:)

我对原始代码进行了很多重构,因此应该有一些错别字或错误。
如果您找到一个,请修改。