gpt4 book ai didi

javascript - 如何避免 `addEventListener` 和 `window.open` 之间的竞争条件

转载 作者:行者123 更新时间:2023-11-29 23:19:33 24 4
gpt4 key购买 nike

作为我网站 OAuth 流程的一部分,我使用 window.open 允许用户登录到第 3 方提供商,并使用 postMessage将身份验证 token 发送回我的网页。基本流程看起来像这样,尽管我删除了与超时、清理、错误处理等相关的额外代码:

const getToken = () => new Promise((resolve, reject) => {
const childWindow = window.open(buildUrl({
url: "https://third-party-provider.com/oauth/authorize",
query: {
redirect_uri: "my-site.com/oauth-callback"
}
})

window.addEventListener('message', event => {
if(
event.origin === window.location.origin &&
event.source === childWindow
) {
if(event.data.error) reject(event.data.error)
else resolve(event.data)
}
})

// Plus some extra code to remove the event listener and close
// the child window.
}

基本思想是,当用户点击授权时,他们将被重定向到 my-site.com/oauth-callback。该页面在服务器端完成 OAuth 流程,然后加载包含少量 javascript 的页面,该页面仅调用 window.opener.postMessage(...)

现在,我的问题的症结在于这里实际上存在竞争条件,至少在理论上是这样。问题是 childWindow 可以假设调用 postMessage 之前 addEventListener 被调用。相反,如果我先调用 addEventListener,它可以在 childWindow 设置之前接收消息,我认为会抛出和异常(exception)?关键问题似乎是 window.open 不是异步的,因此我无法自动生成窗口设置消息处理程序。

目前,我的解决方案是先设置事件处理程序,并假设在执行该函数时不会收到消息。这是一个合理的假设吗?如果不是,是否有更好的方法来确保此流程正确无误?

最佳答案

这里不应该出现竞争条件,因为 window.openwindow.addEventListener 在同一个 tick 中同时出现,而且 Javascript 都是单线程的和不可重入。

如果子窗口确实设法在对 window.open 的调用完成之前发布消息,则该消息将简单地进入当前 Javascript 上下文的事件队列。您的代码仍在运行,因此接下来会调用 addEventListener。最后,在我们在这里看不到的某个 future 时间点,您的代码将控制权返回给浏览器,浏览器结束当前的滴答。

一旦当前滴答结束,浏览器就可以检查事件队列并分派(dispatch)下一个工作(大概是消息)。您的订阅者已经到位,所以一切都很好!

关于javascript - 如何避免 `addEventListener` 和 `window.open` 之间的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51250834/

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