javascript:等待元素的属性准备好继续

use*_*167 5 javascript

我有一个从 3rd 方注入到我的页面的元素的属性:

document.querySelector('#embed-container #mf2-events').jsMF2
Run Code Online (Sandbox Code Playgroud)

jsMF2 被称为注入属性。我需要等到 jsMF2 属性被定义才能使用它。本来,我只是设置了一个超时时间,但是由于很多原因,这是不可取的。有没有办法可以旋转直到属性或设置回调?如果这是一个 C 程序,我会这样写:

    while (document.querySelector('#embed-container #mf2-events').jsMF2 === undefined ||
           document.querySelector('#embed-container #mf2-events').jsMF2 === null) { } 

    // do work
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 5

您不希望忙等待,因为这样就没有其他 JavaScript 可以运行(更不用说浏览器 UI 的大部分),因此不会定义该属性。

理想情况下,提供该属性的任何内容都会触发一个您可以挂钩的事件。我假设你已经看过了,但没有找到。:-)

一旦在ECMAScript6最新的东西(又名“ES6”)的支持成为普遍的(它目前还不是),你可能能够使用Proxy这个(前提是您的目标浏览器允许Proxy在他们的HTML元素实例)。但是Proxy如果不是更长的话,足够广泛的支持将需要几年时间(并且Proxy不能被填充/填充)。(在 ES7 中,您可以使用Object.observe,但据推测Proxy,由当前 [截至 2015 年 6 月] 标准定义的 将在 ES7 技术出现之前得到广泛支持。)

直到/除非您可以使用Proxy,计时器确实是处理这种情况的正确方法。如有必要,它可以是一个非常激进的计时器。

如果已知该元素存在但您正在等待该属性:

check(function(element) {
    // It's there now, use it
    // x = element.jsMF2
});

function check(callback) {
    var element = document.querySelector('#embed-container #mf2-events');
    if (element && 'jsMF2' in element) {
        setTimeout(callback.bind(null, element), 0);
    } else {
        setTimeout(check.bind(null, callback), 0);
    }
}
Run Code Online (Sandbox Code Playgroud)

大多数浏览器会在 JavaScript 线程前几次可用时立即触发该计时器,然后将其限制为至少 4 毫秒的延迟以供后续调用使用。还是蛮快的。

不过,您不必过于激进。与计算机相比,人类的速度很慢,您可能会使用 10、20 甚至 50 毫秒。

如果有任何的财产不会出现的机会,你要停止重复系列的setTimeout最终(第二后,10秒后,30秒后,60秒,无论是适合你的使用情况后)。您可以通过记住开始的时间来做到这一点,如果时间过长,则只需放弃而不是重新安排:

var started = Date.now();

check(function(element) {
    // It's there now, use it
    // x = element.jsMF2
});

function check(callback) {
    var element = document.querySelector('#embed-container #mf2-events');
    if (element && 'jsMF2' in element) {
        setTimeout(callback.bind(null, element), 0);
    } else {
        if (Date.now() - started > 1000) { // 1000ms = one second
            // Fail with message
        } else {
            setTimeout(check.bind(null, callback), 0);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

旁注:查询

var document.querySelector('#embed-container #mf2-events');
Run Code Online (Sandbox Code Playgroud)

……有点奇怪。它说:给我在id mf2-events带有id embed-container. 但是页面上的id必须是唯一的。所以真正说的是“获取#mfs-events元素,但前提是它在#embed-container元素内。”

除非这真的是你的意思,否则速度会更快

var document.getElementById('mf2-events');
Run Code Online (Sandbox Code Playgroud)

......将是要走的路。