document.getElementById returns a null value, but only when executed within a multiline script. Returns correct element when executed by itself

huangapple go评论65阅读模式
英文:

document.getElementById returns a null value, but only when executed within a multiline script. Returns correct element when executed by itself

问题

我正在创建一个脚本,用于在服务器监控网站上自动执行数据输入过程。该网站没有针对这种特定数据输入类型的API,因此我使用JavaScript自动执行鼠标点击和数据输入过程。

脚本为getElement语句返回了正确的document.getElementById("")值。然而,只有在我手动逐行执行时,它才返回正确的值。如果我运行整个脚本,代码就会在某一行上中断。

var namesAndAddresses = { 'DomainName': 'IP' };

//按下侧边栏“添加设备按钮”的函数
function MenuFunction() {

    MenuId = document.getElementById("menurow_Add/Import Devices").firstChild.nextElementSibling;

    MenuId.click()
}
//按下“手动添加设备按钮”的函数
function AddDeviceFunction() {

    AddDeviceButton = document.getElementById("addDeviceButtonId_label");

    AddDeviceButton.click();

}
//添加设备信息然后按下保存按钮的函数
function AddDeviceInformationFunction(domain, address) {

    FQDN = document.getElementById("deviceNameId").value =
        domain; //FQDN;

    deviceClass = document.getElementById("deviceClassId").value =
        "Switch/Router";

    OS = document.getElementById("deviceOsId").value =
        "Other Operating System";

    ipAddress = document.getElementById("customUriId").value =
        address; //DictionaryID;

    licenseMode = document.getElementById("licenseModeId").value =
        "Professional Mode";

    saveButton = document.getElementById("cancelButtonId"); //改成保存按钮

    saveButton.click();
}

//手动等待函数
function pause(milliseconds) {
    var dt = new Date();
    while ((new Date()) - dt <= milliseconds) { /* 什么也不做 */ }
}

//用于添加字典中列出的每个域和IP的for循环
for (var [domainName, IP] of Object.entries(namesAndAddresses)) {

    window.self = document;
    //按下侧边栏“添加设备按钮”的函数
    MenuFunction();

    //在此处插入等待子页面加载
    pause(3000);

    //按下“手动添加设备按钮”的函数 **这是返回null的函数**
    AddDeviceFunction();

    //在此处插入等待对象加载
    pause(5000);

    //添加设备信息然后按下保存按钮的函数
    AddDeviceInformationFunction(domainName, IP);

    //在此处插入等待对象加载

    pause(5000);

};`

以下是HTML代码:

点击此处查看图像描述

我尝试了手动“等待”,因为window.onload不起作用,因为所有HTML都已经加载。我还尝试在循环内添加try/catch语句,以便它可以在10秒的时间内尝试10次。那也没有起作用。

英文:

I am creating a script to automate a data entry process on a server monitoring website. The site does not have an API for this specific data entry type, so I am using JavaScript to automate the mouse clicking and data entry process.

The script returns the correct document.getElementById("") value for getElement statement. However, it only returns the correct value whenever I manually execute line of individually. If I run the entire script, then the code breaks on one single line.

`var namesAndAddresses = { &#39;DomainName&#39;: &#39;IP&#39; };
//Function to press sidebar &quot;add device button&quot;
function MenuFunction() {
MenuId = document.getElementById(&quot;menurow_Add/Import Devices&quot;).firstChild.nextElementSibling;
MenuId.click()
}
//Function to press &quot;add device manually button&quot;
function AddDeviceFunction() {
AddDeviceButton = document.getElementById(&quot;addDeviceButtonId_label&quot;);
AddDeviceButton.click();
}
//Function to add device information and then press the save button
function AddDeviceInformationFunction(domain, address) {
FQDN = document.getElementById(&quot;deviceNameId&quot;).value =
domain; //FQDN;
deviceClass = document.getElementById(&quot;deviceClassId&quot;).value =
&quot;Switch/Router&quot;;
OS = document.getElementById(&quot;deviceOsId&quot;).value =
&quot;Other Operating System&quot;;
ipAddress = document.getElementById(&quot;customUriId&quot;).value =
address; //DictionaryID;
licenseMode = document.getElementById(&quot;licenseModeId&quot;).value =
&quot;Professional Mode&quot;;
saveButton = document.getElementById(&quot;cancelButtonId&quot;); //change to save button
saveButton.click();
}
//manually wait function
function pause(milliseconds) {
var dt = new Date();
while ((new Date()) - dt &lt;= milliseconds) { /* Do nothing */ }
}
//For loop to add each domain and ip that is listed in the dictionary
for (var [domainName, IP] of Object.entries(namesAndAddresses)) {
window.self = document;
//Function to press sidebar &quot;add device button&quot;
MenuFunction();
//Insert wait for sub-page to load here
pause(3000);
//Function to press &quot;add device manually button&quot; **THIS IS THE FUNCTION THAT RETURNS NULL**
AddDeviceFunction();
//Insert wait for objects to load here
pause(5000);
//Function to add device information and then press the save button
AddDeviceInformationFunction(domainName, IP);
//Insert wait for objects to load here
pause(5000);
};`

HTML code is below:

enter image description here

I have tried adding in a manual "wait" because window.onload does not work due to all the HTML being loaded already. I also tried adding a try/catch statement within a loop, so that it could make the attempt 10 times over a period of 10 seconds. That didn't work either.

答案1

得分: 1

你的代码中的 pause 函数是阻塞式的。

这意味着由于它使用 while 循环 "等待",实际上并不是真正的等待,而是在执行许多无用的工作,占用了 CPU 的 100%,阻止其他任何事情加载。

因此,我只能假设加载时应该出现的元素没有机会出现,这意味着 getElementById 返回 null(它们还不存在)。

考虑使用类似 setTimeout 的东西,它会适当等待,而不会阻止其他工作的执行。

将代码末尾的 for 循环替换为:

var entries = Object.entries(namesAndAddresses)
window.self = document;
function processEntry(){
    if(!entries.length){
        // 完成
        return
    }
    
    // 获取(并删除)数组中的第一个元素
    var [domainName, IP] = entries.shift()

    // 按侧边栏 "添加设备" 按钮的功能
    MenuFunction();

    // 使用 setTimeout 等待子页面加载,它会在 3000 毫秒后运行此代码
    setTimeout(function(){
        // 按 "手动添加设备" 按钮的功能 **这个函数返回 null**
        AddDeviceFunction();

        // 等待对象加载
        setTimeout(function(){
            // 添加设备信息,然后按保存按钮的功能
            AddDeviceInformationFunction(domainName, IP);

            // 等待对象加载
            setTimeout(function(){
                // 完成,转到下一个条目
                processEntry();
            }, 5000);
        }, 5000);
    }, 3000);
};
processEntry()

我还建议研究一下 Promises 和 async/await,可以使这段代码看起来更整洁:

function pause(milliseconds) {
    return new Promise(function(finish){
        setTimeout(finish, milliseconds)
    })
}
async function processAllEntries(){
    // 用于添加字典中列出的每个域和 IP 的 for 循环
    for (var [domainName, IP] of Object.entries(namesAndAddresses)) {
    
        window.self = document;
        // 按侧边栏 "添加设备" 按钮的功能
        MenuFunction();
    
        // 等待子页面加载
        await pause(3000);
    
        // 按 "手动添加设备" 按钮的功能 **这个函数返回 null**
        AddDeviceFunction();
    
        // 等待对象加载
        await pause(5000);
    
        // 添加设备信息,然后按保存按钮的功能
        AddDeviceInformationFunction(domainName, IP);
    
        // 等待对象加载
        await pause(5000);
    
    }
}
英文:

Your code's pause function is blocking.

What this means is that since it "waits" using a while loop, it is not actually waiting but doing a lot of useless work, using up 100% of the CPU, and preventing anything else from actually loading.

Because of this, I can only presume the elements that are supposed to appear when loading do not get a chance to, meaning getElementById returns null (they do not exist yet)

Consider using something like setTimeout, which will properly wait, without preventing other work from being done.

Replace your for loop near the end with

var entries = Object.entries(namesAndAddresses)
window.self = document;
function processEntry(){
    if(!entries.length){
        // Done
        return
    }
    
    // Get (and remove) the first element in the array
    var [domainName, IP] = entries.shift()

    //Function to press sidebar &quot;add device button&quot;
    MenuFunction();

    //Wait for sub-page to load using setTimeout, which will run this code after 3000ms
    setTimeout(function(){
        //Function to press &quot;add device manually button&quot; **THIS IS THE FUNCTION THAT RETURNS NULL**
        AddDeviceFunction();

        //Wait for objects to load here
        setTimeout(function(){
            //Function to add device information and then press the save button
            AddDeviceInformationFunction(domainName, IP);

            //Insert wait for objects to load here
            setTimeout(function(){
                // Done, go to next entry
                processEntry();
            }, 5000);
        }, 5000);
    }, 3000);
};
processEntry()

I would also recommend looking into promises and async/await, which can make this code look much neater:

function pause(milliseconds) {
    return new Promise(function(finish){
        setTimeout(finish, milliseconds)
    })
}
async function processAllEntries(){
    //For loop to add each domain and ip that is listed in the dictionary
    for (var [domainName, IP] of Object.entries(namesAndAddresses)) {
    
        window.self = document;
        //Function to press sidebar &quot;add device button&quot;
        MenuFunction();
    
        //Insert wait for sub-page to load here
        await pause(3000);
    
        //Function to press &quot;add device manually button&quot; **THIS IS THE FUNCTION THAT RETURNS NULL**
        AddDeviceFunction();
    
        //Insert wait for objects to load here
        await pause(5000);
    
        //Function to add device information and then press the save button
        AddDeviceInformationFunction(domainName, IP);
    
        //Insert wait for objects to load here
        await pause(5000);
    
    }
}

答案2

得分: 0

你的暂停导致UI无法渲染。你可以创建一个使用await来查找元素的函数。一旦元素可用,它将进行更新。

function addElem() {
  const div = document.createElement('div');
  div.className = 'foo';
  div.textContent = 'hello';
  document.body.append(div);
}

const waitForElem = (selector) => new Promise((resolve, reject) => {
  const check = () => {
    const elem = document.querySelector(selector);
    if (elem) {
      resolve(elem);
    } else {
      window.setTimeout(check, 1);
    }
  };
  check();
});

window.setTimeout(addElem, 5000);

(async function() {
  const el1 = await waitForElem('#bar');
  el1.textContent = 'found 1';

  const el2 = await waitForElem('.foo');
  el2.textContent = 'found 2';
})();
<div id="bar">Test</div>
英文:

Your pause causes the UI not to be able to render. You can make a function that uses await to look for an element. As soon as it is available it will update.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

function addElem() {
const div = document.createElement(&#39;div&#39;);
div.className = &#39;foo&#39;;
div.textContent = &#39;hello&#39;;
document.body.append(div);
}
const waitForElem = (selector) =&gt; new Promise((resolve, reject) =&gt; {
const check = () =&gt; {
const elem = document.querySelector(selector);
if (elem) {
resolve(elem);
} else {
window.setTimeout(check, 1);
}
};
check();
});
window.setTimeout(addElem, 5000);
(async function() {
const el1 = await waitForElem(&#39;#bar&#39;);
el1.textContent = &#39;found 1&#39;;
const el2 = await waitForElem(&#39;.foo&#39;);
el2.textContent = &#39;found 2&#39;;
})();

<!-- language: lang-html -->

&lt;div id=&quot;bar&quot;&gt;Test&lt;/div&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年2月18日 03:43:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75488627.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定