source

요소가 존재할 때까지 함수를 대기시킵니다.

factcode 2022. 9. 14. 22:14
반응형

요소가 존재할 때까지 함수를 대기시킵니다.

다른 캔버스 위에 캔버스를 추가하려고 하는데, 첫 번째 캔버스가 만들어질 때까지 이 기능이 시작되기를 어떻게 기다려야 합니까?

function PaintObject(brush) {

    this.started = false;

    // get handle of the main canvas, as a DOM object, not as a jQuery Object. Context is unfortunately not yet
    // available in jquery canvas wrapper object.
    var mainCanvas = $("#" + brush).get(0);

    // Check if everything is ok
    if (!mainCanvas) {alert("canvas undefined, does not seem to be supported by your browser");}
    if (!mainCanvas.getContext) {alert('Error: canvas.getContext() undefined !');}

    // Get the context for drawing in the canvas
    var mainContext = mainCanvas.getContext('2d');
    if (!mainContext) {alert("could not get the context for the main canvas");}

    this.getMainCanvas = function () {
        return mainCanvas;
    }
    this.getMainContext = function () {
        return mainContext;
    }

    // Prepare a second canvas on top of the previous one, kind of second "layer" that we will use
    // in order to draw elastic objects like a line, a rectangle or an ellipse we adjust using the mouse
    // and that follows mouse movements
    var frontCanvas = document.createElement('canvas');
    frontCanvas.id = 'canvasFront';
    // Add the temporary canvas as a second child of the mainCanvas parent.
    mainCanvas.parentNode.appendChild(frontCanvas);

    if (!frontCanvas) {
        alert("frontCanvas null");
    }
    if (!frontCanvas.getContext) {
        alert('Error: no frontCanvas.getContext!');
    }
    var frontContext = frontCanvas.getContext('2d');
    if (!frontContext) {
        alert("no TempContext null");
    }

    this.getFrontCanvas = function () {
        return frontCanvas;
    }
    this.getFrontContext = function () {
        return frontContext;
    }

캔버스를 작성하는 코드에 액세스 할 수 있는 경우는, 캔버스가 작성되고 나서 곧바로 함수를 호출해 주세요.

그 코드에 액세스 할 수 없는 경우(예:Google 지도와 같은 서드파티 코드인 경우, 간격을 두고 존재 여부를 테스트할 수 있습니다.

var checkExist = setInterval(function() {
   if ($('#the-canvas').length) {
      console.log("Exists!");
      clearInterval(checkExist);
   }
}, 100); // check every 100ms

그러나 대부분의 경우 서드파티 코드에는 로드가 완료되면 (콜백 또는 이벤트 트리거를 통해) 코드를 활성화하는 옵션이 있습니다.거기에 당신의 기능을 넣을 수 있을지도 모릅니다.인터벌 솔루션은 정말 잘못된 솔루션이며 다른 방법이 작동하지 않는 경우에만 사용해야 합니다.

지원해야 하는 브라우저에 따라 MutationObserver 옵션이 있습니다.

편집: 현재 모든 주요 브라우저가 MutationObserver를 지원합니다.

이와 같은 방법으로 효과를 볼 수 있습니다.

// callback executed when canvas was found
function handleCanvas(canvas) { ... }

// set up the mutation observer
var observer = new MutationObserver(function (mutations, me) {
  // `mutations` is an array of mutations that occurred
  // `me` is the MutationObserver instance
  var canvas = document.getElementById('my-canvas');
  if (canvas) {
    handleCanvas(canvas);
    me.disconnect(); // stop observing
    return;
  }
});

// start observing
observer.observe(document, {
  childList: true,
  subtree: true
});

N.B. 이 코드를 직접 테스트해 본 적은 없지만 그게 일반적인 생각입니다

쉽게 확장하여 변경된 DOM 부분만 검색할 수 있습니다. 위해서는, 「」를 합니다.mutations인수, 객체의 배열입니다.

은 최신 할 수 있지만, '어느 브라우저'나 '어느 브라우저'를 더 것 .then먼저 테스트해 보시기 바랍니다.

ES5

function rafAsync() {
    return new Promise(resolve => {
        requestAnimationFrame(resolve); //faster than set time out
    });
}

function checkElement(selector) {
    if (document.querySelector(selector) === null) {
        return rafAsync().then(() => checkElement(selector));
    } else {
        return Promise.resolve(true);
    }
}

ES6

async function checkElement(selector) {
    const querySelector = null;
    while (querySelector === null) {
        await rafAsync();
        querySelector = document.querySelector(selector);
    }
    return querySelector;
}  

사용.

checkElement('body') //use whichever selector you want
.then((element) => {
     console.info(element);
     //Do whatever you want now the element is there
});

요소를 기다리는 보다 현대적인 접근법:

while(!document.querySelector(".my-selector")) {
  await new Promise(r => setTimeout(r, 500));
}
// now the element is loaded

이 코드는 비동기 함수로 랩해야 합니다.

Jamie Hutber의 답변보다 약간 개선된 점이 있습니다.

const checkElement = async selector => {
  while ( document.querySelector(selector) === null) {
    await new Promise( resolve =>  requestAnimationFrame(resolve) )
  }
  return document.querySelector(selector); 
};

사용 방법:

checkElement('.myElement').then((selector) => {
  console.log(selector);
});

MutationObserver를 사용하는 범용 솔루션을 원하는 경우 이 기능을 사용할 수 있습니다.

// MIT Licensed
// Author: jwilson8767

/**
 * Waits for an element satisfying selector to exist, then resolves promise with the element.
 * Useful for resolving race conditions.
 *
 * @param selector
 * @returns {Promise}
 */
export function elementReady(selector) {
  return new Promise((resolve, reject) => {
    const el = document.querySelector(selector);
    if (el) {resolve(el);}
    new MutationObserver((mutationRecords, observer) => {
      // Query for elements matching the specified selector
      Array.from(document.querySelectorAll(selector)).forEach((element) => {
        resolve(element);
        //Once we have resolved we don't need the observer anymore.
        observer.disconnect();
      });
    })
      .observe(document.documentElement, {
        childList: true,
        subtree: true
      });
  });
}

출처 : https://gist.github.com/jwilson8767/db379026efcbd932f64382db4b02853e

elementReady('#someWidget').then((someWidget)=>{someWidget.remove();});

주의: MutationObserver는 뛰어난 브라우저 지원을 제공합니다.https://caniuse.com/ #syslog=syslogobserver

Et voila! :)

하는 것이 .requestAnimationFramesetTimeout이며, 「es6」를 사용하고 있습니다Promises.

es6, 모듈 및 약속:

// onElementReady.js
const onElementReady = $element => (
  new Promise((resolve) => {
    const waitForElement = () => {
      if ($element) {
        resolve($element);
      } else {
        window.requestAnimationFrame(waitForElement);
      }
    };
    waitForElement();
  })
);

export default onElementReady;

// in your app
import onElementReady from './onElementReady';

const $someElement = document.querySelector('.some-className');
onElementReady($someElement)
  .then(() => {
    // your element is ready
  }

plain js and promises:

var onElementReady = function($element) {
  return new Promise((resolve) => {
    var waitForElement = function() {
      if ($element) {
        resolve($element);
      } else {
        window.requestAnimationFrame(waitForElement);
      }
    };
    waitForElement();
  })
};

var $someElement = document.querySelector('.some-className');
onElementReady($someElement)
  .then(() => {
    // your element is ready
  });

여기 관측 가능한 것을 사용한 해결책이 있습니다.

waitForElementToAppear(elementId) {                                          

    return Observable.create(function(observer) {                            
            var el_ref;                                                      
            var f = () => {                                                  
                el_ref = document.getElementById(elementId);                 
                if (el_ref) {                                                
                    observer.next(el_ref);                                   
                    observer.complete();                                     
                    return;                                                  
                }                                                            
                window.requestAnimationFrame(f);                             
            };                                                               
            f();                                                             
        });                                                                  
}                                                                            

이제 글을 쓸 수 있습니다.

waitForElementToAppear(elementId).subscribe(el_ref => doSomethingWith(el_ref);

돔에 이미 렌더링될 때까지 시간 초과를 설정하여 돔이 이미 존재하는지 확인할 수 있습니다.

var panelMainWrapper = document.getElementById('panelMainWrapper');
setTimeout(function waitPanelMainWrapper() {
    if (document.body.contains(panelMainWrapper)) {
        $("#panelMainWrapper").html(data).fadeIn("fast");
    } else {
        setTimeout(waitPanelMainWrapper, 10);
    }
}, 10);

이프타의 또 다른 변종

var counter = 10;
var checkExist = setInterval(function() {
  console.log(counter);
  counter--
  if ($('#the-canvas').length || counter === 0) {
    console.log("by bye!");
    clearInterval(checkExist);
  }
}, 200);

만약 원소가 나타나지 않을 때를 대비해서 무한정 확인은 하지 않습니다.

순수한 약속 기반의 JavaScript 접근법으로 몇 밀리초 동안 기다릴 수 있습니다.

    const waitElementFor = function(query, ms = 3000) { // 3000 === 3 seconds
        return new Promise((resolve) => {
            var waited = 0;
            var el = null;
            var wi = setInterval(function() {
                el = document.querySelector(query);
                if (waited >= ms || el) {
                    clearInterval(wi);
                    if(el) {
                        resolve(el);
                    } else {
                        resolve(null);
                    }
                }
                waited += 10;
            }, 10);  
        });
    }

함수를 사용하려면 비동기 함수에서 다음 코드를 사용하십시오.

var element = await waitElementFor('#elementID');

단편:

const waitElementFor = function(query, ms = 3000) { // 3000 === 3 seconds
    return new Promise((resolve) => {
        var waited = 0;
        var el = null;
        var wi = setInterval(function() {
            el = document.querySelector(query);
            if (waited >= ms || el) {
                clearInterval(wi);
                if(el) {
                    resolve(el);
                } else {
                    resolve(null);
                }
            }
            waited += 10;
        }, 10);  
    });
}

async function snippetTestAyncFunction(){
    var element = await waitElementFor('#elementID');
    console.log(element);
}

snippetTestAyncFunction();

조금 늦었을지도 모릅니다만, 여기 crisjhougton의 간단한 솔루션이 있습니다.이 솔루션은 대기 시간이 끝났을 때 콜백 기능을 실행할 수 있습니다.

https://gist.github.com/chrisjhoughton/7890303

var waitForEl = function(selector, callback) {
  if (jQuery(selector).length) {
    callback();
  } else {
    setTimeout(function() {
      waitForEl(selector, callback);
    }, 100);
  }
};

waitForEl(selector, function() {
  // work the magic
});

콜백 함수에 파라미터를 전달할 필요가 있는 경우 다음과 같이 사용할 수 있습니다.

waitForEl("#" + elDomId, () => callbackFunction(param1, param2));

하지만 조심하세요!이 솔루션은 디폴트로 무한 루프 트랩에 빠질 수 있습니다.

토픽 스타터의 제안에 대한 몇 가지 개선 사항은 GitHub 스레드에서도 제공됩니다.

맛있게 드세요!

이것은 Chrome 콘솔에서 코드를 실행하고 있는 사용자를 위한 것으로, HTML에 하드 코딩되어 있는 것만이 아닙니다.

위의 user993683은 콘솔코드로 동작하는 코드를 제공합니다.비밀번호는 다음과 같습니다.

while(!document.querySelector(".my-selector")) {
  await new Promise(r => setTimeout(r, 500));
}
// now the element is loaded

비동기 함수 안에 있어야 한다고 덧붙였다.Chrome의 콘솔에서 코드를 사용하고 있다면, 사실 기능으로 코드를 포장할 필요가 없습니다.쓰여진 대로 작동합니다.요소가 존재하는지 확인하기 위해 요소에 액세스하기 직전에 코드에 코드를 삽입하기만 하면 됩니다.

유일한 경고는 다른 상황에서만 존재하는 요소에서는 작동하지 않는다는 것입니다.요소가 결코 다운로드 그렇지 않으면 무기한으로, 대기를 중단할 브라우저를 해지해야 할 것 무한 재생할 것이다.여기에서는 당신은 선물이 될 것 특정 요소들에 사용된다.

우리 회사의 형태 페이지는 12명 이상의 분야의 사건 번호를 기입했다.그리고 대본을 배열에 매일 사건 수백개의 숫자 가지고 있다.그 요소에 하지 않는 모든 하중을 동시에 언제"onload"크롬 콘솔 스크립트에서 작동하지 않으면iFrame 신형 SRC을 변화시키고 있습니다.따라서 저에게는 이 메서드가 god-send고 적어도 45분이 한 날, 늙은 제네릭 async 대기 10초 또는 여기서 30초를 오르내리고 로드 시간으로 인해 절약시켜 준다.

제가 필요한 요소의 아이디 나는 그 변화는 일반"querySelector"대신"getElementById" 있다.

while(!document.getElementById("myFrame").contentWindow.document.getElementById('someDocID')) {
      await new Promise(r => setTimeout(r, 500));
    }
// After completing the wait above it is now safe to access the element
document.getElementById("myFrame").contentWindow.document.getElementById('someDocID'
).innerText = "Smith, John R";
// and now click the submit button then change the SRC to a fresh form, and use
//*emphasized text* the code again to wait for it to fully load

모니터에 사과드립니다만, 몇 달 동안 콘솔 스크립트에 대한 조사와 요소 로드를 기다린 끝에 사용자 993683의 함수에 대한 언급을 통해 콘솔 스크립트에 이 코드에 대한 함수가 필요하지 않다는 것을 깨달았습니다.여기서의 목표는 다른 콘솔 스크립트 사용자를 제가 겪었던 것과 같은 학습 곡선으로 저장하는 것뿐입니다.

그냥 사용하다setTimeOut재귀 포함:

waitUntilElementIsPresent(callback: () => void): void {
    if (!this.methodToCheckIfElementIsPresent()) {
        setTimeout(() => this.waitUntilElementIsPresent(callback), 500);
        return;
    }
    callback();
}

사용방법:

this.waitUntilElementIsPresent(() => console.log('Element is present!'));

시행 횟수를 제한할 수 있으므로 제한 시간 이후 요소가 존재하지 않으면 오류가 발생합니다.

waitUntilElementIsPresent(callback: () => void, attempt: number = 0): void {
    const maxAttempts = 10;
    if (!this.methodToCheckIfElementIsPresent()) {
        attempt++;
        setTimeout(() => this.waitUntilElementIsPresent(callback, attempt), 500);
        return;
    } else if (attempt >= maxAttempts) {
        return;
    }
    callback();
}

언급URL : https://stackoverflow.com/questions/16149431/make-function-wait-until-element-exists

반응형