检测是否有任何JavaScript函数正在运行

18

我知道这听起来很奇怪,但我需要知道页面中是否有任何活动/运行的javascript。

我处于这样一种情况:在页面上渲染所有内容和其他脚本完成后,我必须运行我的javascript/jquery代码。

有没有可能检测到这一点?

编辑:

谢谢大家的回答。不幸的是,我找不到解决方案,因为我无法完全控制页面上正在发生的事情。

即使我能够将我的javascript放在页面末尾,我认为这也不会再次成为解决方案。原因是当页面正在呈现时,一个函数被触发,它调用其他函数,它们调用其他函数,依此类推。结果,某些数据是不正确的,这就是为什么我需要运行我的代码以进行更正。

我使用setTimeout等待2秒钟,以确保我的代码最后执行,但这很丑陋...

所以,谢谢大家,但这更多的是系统问题,而不是js。


@Boomer 我需要在各种浏览器上实现这个。 - gotqn
这可能会有所帮助:https://dev59.com/EE_Sa4cB1Zd3GeqP9y3z - Diodeus - James MacFarlane
你所说的“完成”是什么意思?是指当所有脚本都加载完成时吗?如果不是,那么无法确定一个脚本是否已经完成,因为脚本有权订阅非确定性事件(例如用户输入),并在响应该事件时执行一些代码。 - Rich O'Kelly
在 $(document).ready(function () { 开始工作之后,所有元素都已创建,但渲染是另一回事。据我所知,您无法知道浏览器何时完成图像的渲染。 - Kemal Can Kara
据我所知,您无法知道浏览器何时完成呈现图像。只有在所有图片加载完成后,窗口加载事件才会被触发。 - T.J. Crowder
显示剩余3条评论
3个回答

15

网页浏览器上的 JavaScript 是单线程运行的(除非使用 Web Workers),因此,如果你的 JavaScript 代码正在运行,就意味着没有其他 JavaScript 代码在运行。

为了尽可能确保你的脚本在页面上所有其他 JavaScript 文件都被下载、执行并完成所有渲染之后才运行,建议采取以下措施:

  • 将包含你的代码的 script 标签放在文件的最末端。
  • 在标签上使用 deferasync 属性(它们将被不支持它们的浏览器忽略,但目标是让你的脚本尽可能地排在最后)。
  • 通过 DOM2 的方式挂钩 window 的 load 事件(例如,在支持标准的浏览器上使用 addEventListener,或在旧版本的 IE 上使用 attachEvent)。
  • 在 load 事件中,使用 setTimeout 延迟 0ms 后再执行你的代码(实际上并不是真正的零,而是稍微长一点的时间)。

所以,script 标签应该这样写:

<script async defer src="yourfile.js"></script>

...以及yourfile.js

(function() {
    if (window.addEventListener) {
        window.addEventListener("load", loadHandler, false);
    }
    else if (window.attachEvent) {
        window.attachEvent("onload", loadHandler);
    }
    else {
        window.onload = loadHandler; // Or you may want to leave this off and just not support REALLY old browsers
    }

    function loadHandler() {
        setTimeout(doMyStuff, 0);
    }

    function doMyStuff() {
        // Your stuff here. All images in the original markup are guaranteed
        // to have been loaded (or failed) by the `load` event, and you know
        // that other handlers for the `load` event have now been fired since
        // we yielded back from our `load` handler
    }
})();
那并不意味着其他代码不会在以后运行(例如,通过使用setTimeout,就像我们之前所做的那样,但拥有更长的超时时间)。

因此,有一些事情可以尝试最后运行,但我认为除非完全控制页面和正在运行它的脚本,否则没有任何方法可以保证最后运行(从问题中可以看出您没有完全控制)。

(*有一些边缘情况,线程可以在一个地方挂起,然后允许其他代码在另一个地方运行[例如,当ajax调用完成并显示alert消息时,某些浏览器会触发ajax处理程序,即使另一个函数正在等待alert被解除阻塞],但它们是边界情况,仍然只有一个活动任务。)


2

如何知道多个函数都已经执行完毕

如果你需要等待多个API调用或初始化函数完成,这将非常有用。

let processRemining = 0;

async function f1() {
    processRemining++
    await myAsyncFunction()
    processFinished()
}

async function f2() {
    processRemining++
    await myAsyncFunction2()
    processFinished()
}

function processFinished() {
    processRemining--
    setTimeout(() => { // this is not needed is all the functions are async
        if (processRemining === 0) {
            // Code to execute when all the functions have finished executing
        }
    }, 1)
}

f1()
f2()

我经常将它与freezeClic函数结合使用,以防止用户在脚本仍在等待ajax /异步响应时与页面交互(并选择性地显示预加载图标或屏幕)。


2
没有确定的方法可以做到这一点,因为您无法真正知道其他脚本已安排运行的最新时间。您将不得不决定您想要的目标。
您可以尝试在DOM加载时运行脚本之后运行任何其他可能正在运行的内容。
您可以尝试在页面完全加载(包括图像)时运行脚本之后运行任何其他可能正在运行的内容。
没有可靠的、跨浏览器的方法可以知道页面中的脚本使用哪些事件。
在任一情况下,您都要挂钩适当的事件,然后使用setTimeout()在任何其他正在监视这些事件的东西之后尝试运行您的脚本。
因此,例如,如果您决定等待整个页面(包括图像)加载并希望尝试使您的脚本在等待相同事件的任何其他内容之后运行,您将执行以下操作:
window.addEventListener("load", function() {
    setTimeout(function() {
        // put your code here
    }, 1);
}, false);

对于较旧版本的IE,您需要使用attachEvent()

使用此方法时,您不必担心脚本相对于页面中其他脚本的加载位置,因为这将在特定事件后安排您的脚本在特定时间运行。


你不能将超时设置为0,这样它会在堆栈末尾运行吗? - Bradyo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接