Javascript 跳过堆叠重定向,只完成最后一个重定向

Javascript 跳过堆叠重定向,只完成最后一个重定向,javascript,redirect,window.location,Javascript,Redirect,Window.location,如果在JS中堆叠重定向,它将只运行最后一个重定向。你知道为什么吗 考虑以下代码: const redirect = () => { window.location = 'https://www.google.com'; window.location = 'https://www.example.com'; window.location = 'https://www.bing.com'; }; 如果你在浏览器上运行它,你会看到它直接在bing.com上运行,即使你保留了“网

如果在JS中堆叠重定向,它将只运行最后一个重定向。你知道为什么吗

考虑以下代码:

const redirect = () => {
  window.location = 'https://www.google.com';
  window.location = 'https://www.example.com';
  window.location = 'https://www.bing.com';
};
如果你在浏览器上运行它,你会看到它直接在bing.com上运行,即使你保留了“网络”选项卡,你也会看到其他两个位置甚至没有被请求

为什么呢?为什么它会跳过第一个,直接进入最后一个,而不是直接进入第一个


因此,基本上,当您执行window.location=URL时会发生什么,以及还有哪些其他方式可以让我们更好地控制重定向?

重定向是由web浏览器实现的。实现可能更希望完成所有操作并立即开始加载新页面。使用更好的用户体验的另一种方法是让脚本在加载另一个页面之前运行,因为这样对人眼更友好。现在,如果你说

window.location = url1;
//...
window.location = url2;
如果我们假设脚本在请求另一个页面之前运行,那么在重定向开始时,url2将是window.location的新值。一个非常简单的解决方案是执行以下操作:

var redirectPath;
function redirect(path) {
    if (redirectPath === undefined) (window.location = redirectPath = path);
}

您甚至可以扩展它,实现更优雅的功能,但实际上,我们为什么要多次更改window.location的值呢?这听起来像是反模式。

执行类似window.location=http://www.example.com; 不会导致在执行下一个JavaScript语句时处于另一个文档位置的效果。兼容的用户代理不会立即且自动地与当前执行的脚本开关位置相关

根据上述位置分配语句进行的导航过程由指定的几个步骤组成

简而言之,将创建脚本intepreter任务的后台,并再次排队等待执行,与脚本解释器并行处理每个导航窗口的请求

引用上文链接部分定义的程序步骤列表中的步骤7,此处特别感兴趣:

取消任何先前存在但尚未成熟的浏览上下文的尝试,[…] 因此,有理由认为,您的位置分配创建的所有重定向最终都会被后续重定向取消,最后三次这样的尝试除外,可以继续到成熟期

您关于文档重定向如何应对JavaScript语句执行的假设在我看来是有缺陷的

如果您希望根据指定的平台行为,按顺序可靠地编写访问多个位置的脚本,这样您的应用程序在未来几年内工作的可能性更高,我建议您,或者在应用程序文档上创建链接或其他类似链接的元素或iframe,以使用户代理访问您选择的一些URL

访问您控制域之外的URL时,一个有趣的问题是,脚本的作用域是您的Web应用程序,或者充其量是您控制的一个或多个域。一旦用户代理离开您的域,它将在您无法控制的页面上执行您无法控制的脚本,并且不会加载或执行任何脚本

如果您只想获取资源而不重定向顶部窗口,那么使用fetch可以执行以下操作:

function redirect_in_sequence(URLs) {
    function next() {
        fetch(URLs.shift()).then(response => {
            if(URLs.length) next();
        });
    }
}
redirect_in_sequence([ "http://example1.com", "http://example2.com", "http://example3.com" ]);
你的问题问的是为什么,不是什么或如何,所以我就到此为止

在任何情况下,您都应该熟悉脚本执行在用户代理中的工作方式,这与事件排队和调度的方式和时间有关,正如我们在本例中看到的,用户代理如何导航,无论您是在排序的GUI中键入地址还是为document.location或window.location赋值,除其他外。
为了重复我对您的问题的评论,JavaScript执行与严格顺序执行语句是同步的,但是这些语句调用的行为会导致各种并行执行。事实上,在任何时候,一个用户代理都有几组不同类型的后台任务正在进行。可以说,这是有技术和历史原因的,并非所有这些原因都是完全合理的,但我们现在就知道了。

不能保证所有浏览器都能做到这一点。只要使用一个重定向,您就可以完全控制。如果您是Web浏览器,您将如何实现对代码段的解释?它应该在什么时候停止访问一个URL并开始访问另一个URL?应该是任意的时间吗,比如2秒?或者它应该保证它在第一个URL上收到来自Web服务器的响应,并且一旦响应进入下一个URL,依此类推?@amn如果我们考虑到JS是同步的,那么逻辑上应该做的事情是在第一个重定向窗口之后再进入第二个重定向窗口。location=URL
完成了。现在,第一个可以通过两种方式之一完成:1。它成功了,这意味着出于安全原因,前一个URL中的所有剩余代码都将被丢弃,甚至不会计算其他重定向。2.它失败,这意味着执行移动到下一行和下一个重定向。兼容用户代理向位置对象赋值的行为(通常是窗口或文档对象上名为Location的属性)在某种程度上由指定。我还没有阅读和摸索行为的细节,因为摸索很多东西很难,但你可能会在那里找到答案,如果它指定了足够程度的行为,也就是说。JavaScript解释器机器是同步的,而不是它启用的过程,包括切换浏览器上下文-如果您认为浏览器在通过位置分配从新URL获取新资源时会暂停脚本执行,那么您错了-它只是将执行导航的任务排入队列,您的脚本将在该任务可以启动时继续执行,而不是在该任务实际完成时继续执行。这是由您自己的观察支持的,并且在中提到。假设您是一个应用程序的开发人员,该应用程序本身具有lite和pro版本,并且您希望使用deeplinks重定向到应用程序中的特定页面。在这种情况下,您无法从浏览器中知道用户安装了哪个应用程序,因此打开正确应用程序的唯一方法是尝试两个deeplinks。在这种情况下,您需要一个重定向,如果第一个重定向失败,则需要另一个重定向。实现可能更希望完成所有操作并立即开始加载新页面-不,事实并非如此。正如我在回答中提到的,兼容的实现将与自己的行为保持一致,我们应该对此表示感谢——如果我要实现一个Web浏览器,那么当脚本设置位置时,它应该做什么呢?@ChristosMaris您可以通过Javascript发送请求,而无需重定向,并确定答案是什么。或者,您可以在不可见的iFrame中打开一个页面,并在父页面和子页面之间进行通信。@LajosArpad这两种方法不再有效:您无法获取深度链接或使用iFrame打开它。@ChristosMaris是的,您可以。您可以发送AJAX请求并处理响应。我每天都能成功地做到这一点。关于iframe,您可以打开iframe中的任何页面。如果页面和iframe来自同一个域,则可以在两者之间建立通信。如果它们来自不同的域,并且您可以控制这两个域的源代码,那么您可以,然后您可以在这两个域之间发布消息。