1

我正在写一个greasemonkey脚本。最近我两次遇到同样的问题,我不知道为什么会这样。

function colli(){
.....
var oPriorityMass = bynID('massadderPriority');//my own document.getElementById() function
var aPriorities = [];
if (oPriorityMass) {
    for (var cEntry=0; cEntry < oPriorityMass.childNodes.length; cEntry++) {
        var sCollNumber = oPriorityMass.childNodes[cEntry].getAttribute('coll');
        if (bynID('adder' + sCollNumber + '_check').checked)
            aPriorities.push(parseInt(sCollNumber));
    }
}
.....
}

所以这其中的奥秘在于,有一天我oPriorityMass命名为oPririoty. 它工作正常,但整个功能尚未完成,我开始为我的脚本开发另一个功能。这些功能之间没有任何联系。

几天后,我决定回到上面示例中的函数并完成它。我在没有修改任何内容的情况下对其进行了测试,并在 firefox 的 (4) javascript 错误控制台中出现了错误提示oPriority.chilNodes[cEntry] is undefined。注意,几天前我以完全相同的方式对其进行了测试,根本没有这样的问题。

好的,所以,我决定重命名oPriorityoPriorityMass. 神奇的是,问题解决了。

起初我想,也许有 2 个对象有一些冲突,在不同的函数中使用了相同的名称,即使在函数范围之外,它们也以某种方式继续存在。我的脚本目前超过 6000 行,但我进行了搜索,发现oPriority除了这个确切的函数之外没有提到其他任何地方。

有人可以告诉我,这是如何发生的以及为什么会发生这种情况?我提到同样的事情现在发生了两次,它们发生在不同的功能中,但同样的问题node.childNodes[c] is undefined不是nodenull 并且node.childNodes.length显示正确的子数。到底是怎么回事?我该如何避免此类问题?

谢谢

编辑:错误控制台给出的错误是 Error: uncaught exception: TypeError: oPriorityMass.childNodes[cEntry] is undefined

作为对 Brocks 评论的回应: 作为消息GM_log(oPriorityMass.childNodes[cEntry])返回。通常未定义的事物也是undefined如此。node.childNodes[c]

我的脚本创建了一个 div 窗口。后来上面的函数用到了这个div里面的元素。元素确实有唯一的 ID,我 100% 确定原始站点不知道它们。我的脚本有一个开始/停止按钮,可以在需要时运行一个或另一个功能。我现在一直在刷新页面并运行我的脚本功能。我注意到有时(但并非总是)脚本在第一次运行时会因描述的错误而失败,但是,如果我再次运行它(不刷新页面),它就会开始工作。

该页面有一个修改它的javascript。它改变了它的一些元素宽度,所以当浏览器调整大小时它会改变。但我知道它对我的 div 没有影响,因为当我调整浏览器大小时它保持不变。

编辑2

function bynID(sID) {
    return top.document.getElementById(ns(sID));
}
function ns(sText) {
    return g_sScriptName + '_' + sText;
}

ns 函数只是在 ID 前面添加脚本名称。我在创建 HTML 元素时使用它,因此我的元素永远不会与网页具有相同的 id。所以 bynID() 是一个简单的函数,当我需要按 ID 获取元素时,它可以节省一些打字时间。

我已经修改了我的colli()功能以包括检查

if (oPriorityMass) {
    if (!oPriorityMass.childNodes[0]) {
        GM_log('Retrying');
        setTimeout(loadPage,2000);
        return;
    }
    for (var cEntry=0; cEntry < oPriorityMass.childNodes.length; cEntry++) {
        var sCollNumber = oPriorityMass.childNodes[cEntry].getAttribute('coll');
        if (bynID('adder' + sCollNumber + '_check').checked)
            aPriorities.push(parseInt(sCollNumber));
    }
}

loadPage函数执行 1 个 AJAX 调用,然后我对其运行了几个 XPATH 查询,但实际内容从未附加/显示在页面上,只是保留在内部document.createElement('div'),然后此函数调用colli()。所以现在,当我修改了我的函数时,我检查了错误控制台,发现它可能需要 5 次尝试才能开始正常工作。5 x 2 秒,也就是 10 秒。永远不会总是重试 5 次,可能会有所不同 一定是发生了其他事情吗?

4

2 回答 2

0

So, according to your last edit, it now works, with the delay, right?

But when I suggested the delay it was not meant to do (even more?) ajax calls while waiting!!

NOT:

if (!oPriorityMass.childNodes[0]) {
    GM_log('Retrying');
    setTimeout(loadPage,2000);
    return;

More like:

setTimeout (colli, 2000);

So the ajax and the other stuff that loadPage does could explain the excessive delay.


The random behavior could be caused by:

return top.document.getElementById(ns(sID));

This will cause erratic behavior if any frames or iframes are present, and you do not block operation on frames. (If you do block such operation then top is redundant and unnecessary.)
GM does not operate correctly in such cases -- depending on what the script does -- often seeming to "switch" from top scope to frame scope or vice versa.

So, it's probably best to change that to:

return document.getElementById (ns (sID) );


And make sure you have:

if (window.top != window.self)  //-- Don't run on frames or iframes
    return;

as the top lines of code.


Beyond that, it's near impossible to see the problem, because of insufficient information.

Either boil the problem into a Complete, Self Contained, Recipe for duplicating the failure.

OR, post or link to the Complete, Unedited, Script.

于 2011-05-10T01:40:29.487 回答
0

在 Firefox 中,childNodes 可以包含#text 节点。在尝试调用它之前,您应该检查以确保 childNodes[cEntry]具有nodeType == 1或具有方法。getAttribute例如

<div id="d0">
</div>
<div id="d1"></div>

在上述Firefox 和类似浏览器(即基于Gecko 和基于WebKit 的浏览器如Safari)中,d0 有一个子节点,一个文本节点,d1 没有子节点。

所以我会做类似的事情:

var sCollNumber, el0, el1;

if (oPriorityMass) {
    for (var cEntry=0; cEntry < oPriorityMass.childNodes.length; cEntry++) {
        el0 = oPriorityMass.childNodes[cEntry];

        // Make sure have an HTMLElement that will
        // have a getAttribute method
        if (el0.nodeType == 1) {
          sCollNumber = el0.getAttribute('coll');
          el1 = bynID('adder' + sCollNumber + '_check');

         // Make sure el1 is not falsey before attempting to
         // access properties
         if (el1 && el1.checked)

            // Never call parseInt on strings without a radix
            // Or use some other method to convert to Number
            aPriorities.push(parseInt(sCollNumber, 10));
    }
}

鉴于它sCollNumber似乎是一个字符串整数(只是猜测,但似乎很可能),您还可以使用:

Number(sCollNumber)

或者

+sCollNumber

哪个适合并且更易于维护。

于 2011-05-08T11:58:38.630 回答