Пока переменная не определена - подождите - PullRequest
44 голосов
/ 05 сентября 2011

У меня есть событие click, которое автоматически запускается из другого места в первый раз.Моя проблема в том, что он запускается слишком рано, поскольку необходимые переменные все еще определяются Flash и веб-службами.Итак, сейчас у меня есть:

(function ($) {
    $(window).load(function(){
        setTimeout(function(){
            $('a.play').trigger("click");
        }, 5000);
    });
})(jQuery);

Проблема в том, что 5 секунд для человека с медленным интернет-соединением могут быть слишком быстрыми, и наоборот, для человека с быстрым интернет-соединением - слишком медленными.

Итак, как мне сделать задержку или тайм-аут, пока не будет определено someVariable?

Ответы [ 11 ]

89 голосов
/ 05 сентября 2011

Следующее будет искать переменную, пока она не будет найдена. Проверяется каждые 0,25 секунды.

function waitForElement(){
    if(typeof someVariable !== "undefined"){
        //variable exists, do what you want
    }
    else{
        setTimeout(waitForElement, 250);
    }
}
21 голосов
/ 05 сентября 2011

Я бы предпочел этот код:

function checkVariable() {

   if (variableLoaded == true) {
       // Here is your next action
   }
 }

 setTimeout(checkVariable, 1000);
6 голосов
/ 06 июля 2018

С Ecma Script 2017 Вы можете использовать async-await и, будучи вместе, сделать это И пока не произойдет сбой или не заблокируется программа, даже переменная никогда не будет истинной

//First define some delay function which is called from async function
function __delay__(timer) {
    return new Promise(resolve => {
        timer = timer || 2000;
        setTimeout(function () {
            resolve();
        }, timer);
    });
};

//Then Declare Some Variable Global or In Scope
//Depends on you
let Variable = false;

//And define what ever you want with async fuction
async function some() {
    while (!Variable)
        await __delay__(1000);

    //...code here because when Variable = true this function will
};
////////////////////////////////////////////////////////////
//In Your Case
//1.Define Global Variable For Check Statement
//2.Convert function to async like below

var isContinue = false;
setTimeout(async function () {
    //STOPT THE FUNCTION UNTIL CONDITION IS CORRECT
    while (!isContinue)
        await __delay__(1000);

    //WHEN CONDITION IS CORRECT THEN TRIGGER WILL CLICKED
    $('a.play').trigger("click");
}, 1);
/////////////////////////////////////////////////////////////

Также вам не нужно использовать setTimeout, просто сделайте функцию ready асинхронной ...

3 голосов
/ 20 мая 2019

async, await реализация, улучшение по сравнению с @ ответом Топрака

(async() => {
    console.log("waiting for variable");
    while(!window.hasOwnProperty("myVar")) // define the condition as you like
        await new Promise(resolve => setTimeout(resolve, 1000));
    console.log("variable is defined");
})();
console.log("above code doesn't block main function stack");

После повторного рассмотрения вопроса ОП. На самом деле есть лучший способ реализовать то, что предполагалось: «обратный вызов набора переменных». Хотя приведенный ниже код работает только в том случае, если нужная переменная инкапсулируется объектом (или окном) вместо объявления let или var (я оставил первый ответ, потому что я просто улучшал существующие ответы, не читая оригинал вопрос):

let obj = encapsulatedObject || window;
Object.defineProperty(obj, "myVar", {
    configurable: true,
    set(v){
        Object.defineProperty(obj, "myVar", {
            configurable: true, enumerable: true, writable: true, value: v });
        console.log("window.myVar is defined");
    }
});

см. Object.defineProperty или используйте es6 proxy (что, вероятно, излишне)

3 голосов
/ 02 сентября 2016

Вот пример, где вся логика ожидания, пока переменная не установлена, откладывается до функции, которая затем вызывает обратный вызов, который выполняет все остальное, что нужно программе - если вам нужно загрузить переменные, прежде чем делать что-то еще, это чувствуеткак изящный способ сделать это, так что вы отделяете загрузку переменной от всего остального, при этом гарантируя, что «все остальное» по сути является обратным вызовом.

var loadUser = function(everythingElse){
    var interval = setInterval(function(){
      if(typeof CurrentUser.name !== 'undefined'){
        $scope.username = CurrentUser.name;
        clearInterval(interval);
        everythingElse();
      }
    },1);
  };

  loadUser(function(){

    //everything else

  });
2 голосов
/ 06 сентября 2014

Короткий путь:

   var queue = function (args){
      typeof variableToCheck !== "undefined"? doSomething(args) : setTimeout(function () {queue(args)}, 2000);
};

Вы также можете передавать аргументы

2 голосов
/ 05 сентября 2011

Вы можете использовать это:

var refreshIntervalId = null;
refreshIntervalId = setInterval(checkIfVariableIsSet, 1000);

var checkIfVariableIsSet = function()
{
    if(typeof someVariable !== 'undefined'){
        $('a.play').trigger("click");
        clearInterval(refreshIntervalId);
    }
};
2 голосов
/ 05 сентября 2011

Вместо использования события загрузки Windows используйте событие ready в документе.

$(document).ready(function(){[...]});

Это должно сработать, когда все в DOM готово к работе, включая медиа-контент полностью загруженный.

0 голосов
/ 22 февраля 2019
Object.defineProperty(window, 'propertyName', {
    set: value => {
        this._value = value;
        // someAction();
    },
    get: () => this._value
});

или даже если вы просто хотите, чтобы это свойство передавалось в качестве аргумента функции, и вам не нужно, чтобы оно определялось для глобального объекта:

Object.defineProperty(window, 'propertyName', { set: value => someAction(value) })

Однако, поскольку в вашем примере вы, кажется, хотите выполнить действие при создании узла, я бы посоветовал вам взглянуть на MutationObservers .

0 голосов
/ 24 октября 2018

Я проголосовал за @ dnuttle's ответ , но в итоге использовал следующую стратегию:

// On doc ready for modern browsers
document.addEventListener('DOMContentLoaded', (e) => {
  // Scope all logic related to what you want to achieve by using a function
  const waitForMyFunction = () => {
    // Use a timeout id to identify your process and purge it when it's no longer needed
    let timeoutID;
    // Check if your function is defined, in this case by checking its type
    if (typeof myFunction === 'function') {
      // We no longer need to wait, purge the timeout id
      window.clearTimeout(timeoutID);
      // 'myFunction' is defined, invoke it with parameters, if any
      myFunction('param1', 'param2');
    } else {
      // 'myFunction' is undefined, try again in 0.25 secs
      timeoutID = window.setTimeout(waitForMyFunction, 250);
    }
  };
  // Initialize
  waitForMyFunction();
});

Проверено и работает! ;)

Суть: https://gist.github.com/dreamyguy/f319f0b2bffb1f812cf8b7cae4abb47c

...