【问题标题】:JS: How to WAIT for an element to appear, and then do something IN a loopJS:如何等待元素出现,然后在循环中执行某些操作
【发布时间】:2018-01-09 22:54:46
【问题描述】:

这不是我第一次遇到这个问题,经过彻底搜索,我看到很多人遇到同样的问题,但没有解决方案。我希望有一个我以前从未听说过的神奇 API,或者也许有人告诉我我只是老做错了。 :-P

我有一个脚本,它模拟单击元素作为循环块中的第一个动作。

这会导致出现自定义模式对话框。

然后我需要对这个对话框做一些事情,然后模拟一个按钮的点击。

for (day in daysOfWeek) {
        if (daysOfWeek.hasOwnProperty(day)) {
            daysOfWeek[day].click();
            fillOutTime(dailyTimes);
        }
    }

在这里,我将简化 fillOutTime 中的代码并将其包含在循环中,以便您可以看到我在做什么:

var day, submitButton;
for (day in daysOfWeek) {
    if (daysOfWeek.hasOwnProperty(day)) {
        daysOfWeek[day].click(); //opens dialog
        //fill out some stuff
        submitButton = document.getElementById('time_entry_submit'); //get submit button
        submitButton.click(); //click the submit button
    }
}

但是,在第一次单击之后,对话框异步加载显然存在延迟。

我想做的是等到这个对话框出现,然后执行循环中的其余代码。


好的,这是我已经尝试过的:

  1. setTimeout() 和 setInterval() - 这些当然不起作用,因为它们是异步的,所以循环只是以超高速将这些异步事件排队。

    李>
  2. 自定义睡眠功能(见下文)。这只是锁定浏览器,因此对话框在完成之前不会开始加载。我最终遇到了同样的问题,即其余代码在加载之前仍在运行。


function sleep(milliseconds) {
    var start = new Date().getTime();
    for (var i = 0; i < 1e7; i++) {
        if ((new Date().getTime() - start) > milliseconds) {
            break;
        }
    }
}

任何建议都将不胜感激!

【问题讨论】:

  • 我不能完全理解您的问题,因为如果您使用动画,您可以捕获“animationend”事件,但如果您只是应用“显示:块”或"visibility: visible",那么您可以在更改属性的行之后直接调用您的函数。另一个简单的答案是使用回调,在引发“点击”事件时发送的“事件”变量中,您可以添加个性化属性。类似于: e.personalCallback = function () { .... }; element.click(e);你可以在你的听众中使用“personalCallback”
  • 我不明白为什么它不适用于 setTimeout()。模态通常以毫秒为单位打开,默认为 400 毫秒,“快”为 200 毫秒,“慢”为 600 毫秒。我认为您在变量上有范围问题。但是您没有提供足够的代码来确定。我认为没有人能正确回答您,因此我将您的问题投给了 unclear

标签: javascript jquery loops asynchronous synchronous


【解决方案1】:

我不是很关注,但是如果 DOM 容器元素在那里并且它异步加载它的内容,那么您可以添加一个事件侦听器来侦听加载,然后单击它:

var day, submitButton;
for (day in daysOfWeek) {
    if (daysOfWeek.hasOwnProperty(day)) {
      daysOfWeek[day].addEventListener('load', function(){
              submitButton = document.getElementById('time_entry_submit');
              submitButton.click(); //click the submit button
              });
       daysOfWeek[day].click(); //opens dialog

    }
}

希望这会有所帮助!

【讨论】:

  • 有人愿意解释为什么这个答案被否决了吗?
【解决方案2】:

您可能正在寻找类似Promise 的东西。我使用以下向后兼容的代码:

//<![CDATA[
/* external.js */
var doc, bod, M, I, Fulfill, old = onload; // for use on other page loads
onload = function(){
if(old)old(); // change old var name if using technique on other pages
doc = document; bod = doc.body;
M = function(tag){
  return doc.createElement(tag);
}
I = function(id){
  return doc.getElementById(id);
}
Fulfill = function(fulfillDenyFunc){
  var t = this, df = [];
  this.fulfilled = false;
  fulfillDenyFunc(function(){
    for(var i=0,l=df.length; i<l; i++){
      df[i]();
    }
    t.fulfilled = true;
  }, function(){
    t.fulfilled = false;
  });
  this.then = function(doFunc){
    if(this.fulfilled){
      doFunc();
    }
    else{
      df.push(doFunc);;
    }
    return this;
  }
}
var out = I('out'), loop = I('loop'), r = '', im = M('img');
im.width = 510; im.height = 340; im.alt = im.title = 'lonely boat';
var yup = new Fulfill(function(resolve, reject){
  im.onload = function(){
    out.appendChild(this); resolve();
  }
  im.src = 'https://cdn.pixabay.com/photo/2017/01/19/12/04/boot-1992136__340.jpg';
  im.onerror = function(){
    reject();
  }
}); // now use yup anywhere below the var
yup.then(function(){
  for(i=0,l=50; i<l; i++){
    r += i+'<br />';
  }
  loop.innerHTML = r;
});
}
//]]>
/* external.css */
html,body{
  padding:0; margin:0;
}
body{
  background:#000; overflow-y:scroll;
}
.main{
  width:936px; background:#ccc; padding:20px; margin:0 auto;
}
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
  <head>
    <meta http-equiv='content-type' content='text/html;charset=utf-8' />
    <meta name='viewport' content='width=device-width' />
    <title>Test Template</title>
    <link type='text/css' rel='stylesheet' href='external.css' />
    <script type='text/javascript' src='external.js'></script>
  </head>
<body>
  <div class='main'>
    <div id='out'></div>
    <div id='loop'></div>
  </div>
</body>
</html>

【讨论】:

    【解决方案3】:

    您要做的是处理每个元素,单击,等待对话框,然后继续处理下一个元素。因此,使用 for 循环将无济于事。

    一种解决方案是使用递归函数,该函数将不断调用队列中的下一项,直到到达最后一个元素。 等待多长时间取决于您的具体情况。我只假设一秒钟的等待时间。

    我无法测试以下功能。 另一种方法是使用 Promise。

    var submitButton, index = 0, days = Object.keys(daysOfWeek);
    
    function process(day) {
      if (!day) {
        return;
      }
    
      if (daysOfWeek.hasOwnProperty(day)) {
        daysOfWeek[day].click(); //opens dialog
        //fill out some stuff
        submitButton = document.getElementById('time_entry_submit');
        submitButton.click(); //click the submit button
        setTimeout(function() {
          process(days[index++]);
        }, 1000);
      } else {
        process(days[index++]);
      }
    };
    
    process(days[index++]);

    【讨论】:

      【解决方案4】:

      不确定这个问题,但我想我理解这个问题,答案可能是观察主机/父元素上的 DOM 突变。

      例如:

          observer = new MutationObserver(waitForMarker);
          observer.observe(mapDiv, {
                          childList     : true,
                          subtree       : true ,
                          attributes    : true ,
                          characterData : false
                          })
      
      function waitForMarker(mutations, myInstance) {
          outer:
          for (var i=0; i<mutations.length; i++){
              if (mutations[i].type           == "attributes" && 
                  mutations[i].target.tagName == "IMG"        &&
                  mutations[i].target.src.toLowerCase().indexOf(MARKER_SRC) != -1){
                  console.log("result")
                  myInstance.disconnect();
                  setTimeout(plotTrip,0)
                  break outer;
              }
              if (mutations[i].type != "childList" ||
                  mutations[i].addedNodes.length   == 0) 
                  continue;
              for (var j=0; j<mutations[i].addedNodes.length; j++) {
                  var node = mutations[i].addedNodes[j];
                  if (node.tagName == "DIV" && node.firstChild && node.firstChild.tagName == "IMG" &&
                      node.firstChild.src.toLowerCase().indexOf(MARKER_SRC) != -1){
                      console.log(node.firstChild.src);
                      myInstance.disconnect();
                      setTimeout(plotTrip,0)
                      break outer;
                  }
              }
          }
      }   
      

      【讨论】:

        猜你喜欢
        • 2012-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多