gpt4 book ai didi

javascript - 异步和顺序触发Vuex Action -我不了解什么?

转载 作者:行者123 更新时间:2023-12-01 00:52:18 25 4
gpt4 key购买 nike

我有一个Vuex商店,我正在尝试从Firebase实时数据库中获取数据。我最初是在获取用户信息,但是此后,我想获取一些其他信息,这些信息取决于所获取的初始数据。

从代码中可以看到,我正在尝试使用async / await来执行此操作,但是,每当触发created()挂钩中的两个动作时,用户的信息都不会初始化,因此第二个动作将失败。

我的用户商店

    async fetchCreds({ commit }) {
try {
firebase.auth().onAuthStateChanged(async function(user) {
const { uid } = user
const userDoc = await users.doc(uid).get()

return commit('SET_USER', userDoc.data())
})
} catch (error) {
console.log(error)
commit('SET_USER', {})
}
}


我的俱乐部行动取决于上述呼吁

    async fetchClubInformation({ commit, rootState }) {
try {
const clubIDForLoggedInUser = rootState.user.clubId
const clubDoc = await clubs.doc(clubIDForLoggedInUser).get()

return commit('SET_CLUB_INFO', clubDoc.data())
} catch (error) {
console.log(error)
}
}
}


在组件的created()方法中调用的方法。

  created: async function() {
await this.fetchCreds();
await this.fetchClubInformation();
this.loading = false;
}


我有一种根本上误解了异步/等待的感觉,但是我不明白代码中有什么不正确-任何帮助或建议都将不胜感激。

最佳答案

我对Firebase并不是特别熟悉,但是在仔细研究了源代码之后,我认为我可以对您的问题有所了解。

首先,请考虑以下示例:

async function myFn (obj) {
obj.method(function () {
console.log('here 1')
})

console.log('here 2')
}

await myFn(x)
console.log('here 3')


问题:您将以什么顺序查看日志消息?

好吧 here 2肯定会在 here 3之前出现,但是从上面的代码中无法确定 here 1何时会出现。这取决于 obj.method对传递的功能的处理方式。它可能根本不会调用它。它可能会同步调用它(例如Array的 forEach方法),在这种情况下 here 1会出现在其他消息之前。如果它是异步的(例如计时器,服务器调用),则 here 1可能会在 here 3之后很长时间不显示。

如果 async修饰符没有返回Promise本身,则将从函数隐式返回Promise。该Promise的解析值将是该函数返回的值,并且Promise将在该函数返回的位置解析。对于结尾没有 return的函数,等效于以 return undefined结尾。

因此,为了强调关键点,异步函数返回的Promise将仅等待该函数返回。

方法 onAuthStateChanged异步调用其回调,因此该回调中的代码要等到周围函数完成后才能运行。没有什么可以告诉隐式返回的Promise等待该回调被调用的。回调中的 await无关紧要,因为该函数尚未被调用。

Firebase广泛使用Promises,因此通常的解决方案将是 returnawait相关Promise:

// Note: This WON'T work, explanation follows
return firebase.auth().onAuthStateChanged(async function(user) {


// Note: This WON'T work, explanation follows
await firebase.auth().onAuthStateChanged(async function(user) {


这在这里不起作用,因为 onAuthStateChanged实际上没有返回Promise,而是返回了 unsubscribe函数。

当然,您可以自己创建一个新的Promise并以这种方式“修复”。但是,使用 new Promise创建新的Promises通常被认为是代码气味。通常,只有在包装不正确支持Promises的代码时才需要这样做。如果我们正在使用具有适当Promise支持的库(如此处所示),那么我们就不需要创建任何Promises。

那么 onAuthStateChanged为什么不返回Promise?

因为这是观看所有登录/注销事件的一种方式。每次用户登录或注销时,都会调用回调。它并不是用来观看特定登录的方式。一个Promise只能被解析为一个值。因此,尽管可以使用Promise对单个登录事件进行建模,但在观看所有登录/注销事件时却毫无意义。

因此, fetchCreds正在注册以接收有关所有登录/注销事件的通知。它对返回的 unsubscribe函数不做任何事情,因此大概它将一直监听所有此类事件,直到重新加载页面为止。如果多次调用 fetchCreds,它将继续添加越来越多的侦听器。

如果您正在等待用户完成登录,那么我建议您直接等待。 firebase.auth()有多种以前缀 signIn开头的方法,例如 signInWithEmailAndPassword,并且它们确实返回一个Promise,该Promise在用户完成登录后进行解析。解析的值提供对包括用户在内的各种信息的访问。我不知道您使用的是哪种方法,但是所有方法的想法都差不多。

但是,可能您真的只是对获取当前用户的详细信息感兴趣。如果仅此而已,则完全不需要使用 onAuthStateChanged。您应该只能够使用 currentUser属性获取副本。像这样:

async fetchCreds({ commit }) {
try {
const { uid } = firebase.auth().currentUser
const userDoc = await users.doc(uid).get()

commit('SET_USER', userDoc.data())
} catch (error) {
console.log(error)
commit('SET_USER', {})
}
}


正如我已经提到的那样,这取决于用户已经登录的假设。如果这不是一个安全的假设,那么您可能要考虑等到登录完成后再创建需要用户凭据的组件。

更新:

来自评论的问题:


  如果obj.method()调用是异步的,并且我们确实在其中等待回调函数,是否可以确保外部异步函数(myFn)在内部函数完成之前从未解析?


我不确定您在这里问什么。

需要明确的是,我对 async和异步的使用非常谨慎。诸如 setTimeout的功能将被视为异步的,但不是 async

async / await只是Promises中的很多语法糖。您并不是真正在等待功能,而是在等待Promise。当我们谈论等待 async函数时,我们实际上是在等待等待Promise返回解决。

因此,当您说等待回调函数时,并不清楚是什么意思。您要尝试哪个承诺 await

async修饰符放在函数上并不能使其神奇地等待事件。它只会在遇到 await时等待。您仍然可以在 async函数中进行其他异步调用,并且与普通函数一样,这些调用将在函数返回后执行。 “暂停”的唯一方法是 await一个承诺。

await放在另一个函数(甚至是嵌套函数)中,除非外部函数已经在等待内部函数,否则外部函数是否在等待中不会有任何区别。在后台,这仅仅是Promises链接 then调用。每当您编写 await时,您都只是向Promise添加另一个 then调用。但是,除非Promise与外部 async函数返回的Promise处于同一链中,否则这将不会具有预期的效果。它只需要丢失一个链接即可使链失效。

因此,修改我之前的示例:

async function myFn (obj) {
await obj.method(async function () {
await somePromise

// ...
})

// ...
}

await myFn(x)


请注意,这里有3个函数: myFnmethod和传递给 method的回调。问题是, await myFn(x)是否会等待 somePromise

从上面的代码我们实际上无法分辨。这将取决于 method内部执行的操作。例如,如果 method看起来像这样,那么它将仍然不起作用:

function method (callback) {
setTimeout(callback, 1000)
}


async放在 method上无济于事,这只会使其返回Promise,但Promise仍不会等待计时器触发。

我们的Promise链断开了。 myFn和回调都在创建链的各个部分,但是除非 method将那些Promises链接在一起,否则它将不起作用。

另一方面,如果编写了 method来返回一个适当的Promise,它等待回调完成,那么我们将获得目标行为:

function method (callback) {
return someServerCallThatReturnsAPromise().then(callback)
}


我们可以在这里使用 async / await,但是没有必要,因为我们可以直接返回Promise。


  另外,如果在异步myFn函数中没有返回任何内容,这是否意味着它将立即解析为undefined?


这里的术语“立即”定义不明确。


如果一个函数没有在末尾返回任何内容,则相当于在末尾有 return undefined
async函数返回的Promise将在函数返回时解析。
已解决的Promise值将是返回的值。


因此,如果您不返回任何内容,它将解析为 undefined。在功能结束之前不会进行解析。如果该函数不包含任何 await调用,则这将“立即”发生,与同步函数“立即”返回的意义相同。

但是, await只是 then调用周围的语法糖,并且 then调用始终是异步的。因此,尽管Promise可能“立即”解决,但 await仍然需要等待。这是一个很短的等待,但它不是同步的,其他代码可能有机会同时运行。

考虑以下:

const myFn = async function () {
console.log('here 3')
}

console.log('here 1')

Promise.resolve('hi').then(() => {
console.log('here 4')
})

console.log('here 2')

await myFn()

console.log('here 5')


日志消息将按照编号顺序显示。因此,即使 myFn立即解决,您仍然会在 here 4here 3之间跳转 here 5

关于javascript - 异步和顺序触发Vuex Action -我不了解什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56878908/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com