英文:
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 = { 'DomainName': 'IP' };
//Function to press sidebar "add device button"
function MenuFunction() {
MenuId = document.getElementById("menurow_Add/Import Devices").firstChild.nextElementSibling;
MenuId.click()
}
//Function to press "add device manually button"
function AddDeviceFunction() {
AddDeviceButton = document.getElementById("addDeviceButtonId_label");
AddDeviceButton.click();
}
//Function to add device information and then press the save button
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"); //change to save button
saveButton.click();
}
//manually wait function
function pause(milliseconds) {
var dt = new Date();
while ((new Date()) - dt <= 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 "add device button"
MenuFunction();
//Insert wait for sub-page to load here
pause(3000);
//Function to press "add device manually button" **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:
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 "add device button"
MenuFunction();
//Wait for sub-page to load using setTimeout, which will run this code after 3000ms
setTimeout(function(){
//Function to press "add device manually button" **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 "add device button"
MenuFunction();
//Insert wait for sub-page to load here
await pause(3000);
//Function to press "add device manually button" **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('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';
})();
<!-- language: lang-html -->
<div id="bar">Test</div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论