虽然变量未定义 - 等待

发布于 2024-12-02 18:13:57 字数 400 浏览 0 评论 0原文

我有一个第一次从另一个地方自动触发的 click 事件。我的问题是它运行得太快,因为所需的变量仍在由 Flash 和 Web 服务定义。所以现在我有:

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

问题是,对于互联网连接速度慢的人来说 5 秒可能太快了,反之亦然,对于互联网连接速度快的人来说,它太慢了。

那么在定义 someVariable 之前我应该​​如何进行延迟或超时呢?

I have a click event that is triggered from another place automatically for the first time. My problem is that it runs too soon, since the required variables are still being defined by Flash and web services. So right now I have:

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

The problem is that 5 seconds for a person with a slow internet connection could be too fast and vice versa, for a person with a fast internet connection, it's too slow.

So how should I do the delay or timeout until someVariable is defined?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

北凤男飞 2024-12-09 18:13:57

下面将继续寻找 someVariable 直到找到为止。它每 0.25 秒检查一次。

function waitForElement(){
    if(typeof someVariable !== "undefined"){
        //variable exists, do what you want
    }
    else{
        setTimeout(waitForElement, 250);
    }
}

The following will keep looking for someVariable until it is found. It checks every 0.25 seconds.

function waitForElement(){
    if(typeof someVariable !== "undefined"){
        //variable exists, do what you want
    }
    else{
        setTimeout(waitForElement, 250);
    }
}
水波映月 2024-12-09 18:13:57

async,await 实施,改进 @Toprak 的回答

(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");

重新审视OP的问题后。实际上有一种更好的方法来实现预期目的:“变量集回调”。尽管下面的代码仅在所需变量由对象(或窗口)封装而不是由 letvar 声明时才有效(我留下了第一个答案,因为我只是在没有实际阅读原始问题的情况下对现有答案进行改进):

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 代理 (这可能是矫枉过正)


如果您正在寻找更多:

/**
 * combining the two as suggested by @Emmanuel Mahuni,
 * and showing an alternative to handle defineProperty setter and getter
 */


let obj = {} || window;
(async() => {
  let _foo = await new Promise(res => {
    Object.defineProperty(obj, "foo", { set: res });
  });
  console.log("obj.foo is defined with value:", _foo);
})();
/*
IMPORTANT: note that obj.foo is still undefined
the reason is out of scope of this question/answer
take a research of Object.defineProperty to see more
*/

// TEST CODE

console.log("test start");
setTimeout(async () => {
  console.log("about to assign obj.foo");
  obj.foo = "Hello World!";
  // try uncomment the following line and compare the output
  // await new Promise(res => setTimeout(res));
  console.log("finished assigning obj.foo");
  console.log("value of obj.foo:", obj.foo); // undefined
  // console: obj.foo is defined with value: Hello World!
}, 2000);

async, await implementation, improvement over @Toprak's answer

(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");

After revisiting the OP's question. There is actually a better way to implement what was intended: "variable set callback". Although the below code only works if the desired variable is encapsulated by an object (or window) instead of declared by let or var (I left the first answer because I was just doing improvement over existing answers without actually reading the original question):

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");
    }
});
    

see Object.defineProperty
or use es6 proxy (which is probably overkill)


If you are looking for more:

/**
 * combining the two as suggested by @Emmanuel Mahuni,
 * and showing an alternative to handle defineProperty setter and getter
 */


let obj = {} || window;
(async() => {
  let _foo = await new Promise(res => {
    Object.defineProperty(obj, "foo", { set: res });
  });
  console.log("obj.foo is defined with value:", _foo);
})();
/*
IMPORTANT: note that obj.foo is still undefined
the reason is out of scope of this question/answer
take a research of Object.defineProperty to see more
*/

// TEST CODE

console.log("test start");
setTimeout(async () => {
  console.log("about to assign obj.foo");
  obj.foo = "Hello World!";
  // try uncomment the following line and compare the output
  // await new Promise(res => setTimeout(res));
  console.log("finished assigning obj.foo");
  console.log("value of obj.foo:", obj.foo); // undefined
  // console: obj.foo is defined with value: Hello World!
}, 2000);

几味少女 2024-12-09 18:13:57

我更喜欢这段代码:

function checkVariable() {

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

 setTimeout(checkVariable, 1000);

I would prefer this code:

function checkVariable() {

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

 setTimeout(checkVariable, 1000);
逆流 2024-12-09 18:13:57

我更喜欢这样简单的东西:

function waitFor(variable, callback) {
  var interval = setInterval(function() {
    if (window[variable]) {
      clearInterval(interval);
      callback();
    }
  }, 200);
}

然后将其与 someVariable 的示例变量一起使用:

waitFor('someVariable', function() {
  // do something here now that someVariable is defined
});

请注意,您可以进行各种调整。在上面的 setInterval 调用中,我传递了 200 作为间隔函数应该运行的频率。在检查变量之前,还有一个固有的延迟(约 200 毫秒)——在某些情况下,最好立即检查它,这样就不会出现延迟。

I prefer something simple like this:

function waitFor(variable, callback) {
  var interval = setInterval(function() {
    if (window[variable]) {
      clearInterval(interval);
      callback();
    }
  }, 200);
}

And then to use it with your example variable of someVariable:

waitFor('someVariable', function() {
  // do something here now that someVariable is defined
});

Note that there are various tweaks you can do. In the above setInterval call, I've passed 200 as how often the interval function should run. There is also an inherent delay of that amount of time (~200ms) before the variable is checked for -- in some cases, it's nice to check for it right away so there is no delay.

上课铃就是安魂曲 2024-12-09 18:13:57

使用 Ecma Script 2017 您可以使用 async-await 和 while 一起来做到这一点
虽然不会崩溃或锁定程序,但即使变量永远不会为真

//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 只需使准备功能异步...

With Ecma Script 2017 You can use async-await and while together to do that
And while will not crash or lock the program even variable never be true

//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);
/////////////////////////////////////////////////////////////

Also you don't have to use setTimeout in this case just make ready function asynchronous...

卷耳 2024-12-09 18:13:57

你可以使用这个:

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

var checkIfVariableIsSet = function()
{
    if(typeof someVariable !== 'undefined'){
        $('a.play').trigger("click");
        clearInterval(refreshIntervalId);
    }
};

You can use this:

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

var checkIfVariableIsSet = function()
{
    if(typeof someVariable !== 'undefined'){
        $('a.play').trigger("click");
        clearInterval(refreshIntervalId);
    }
};
忆离笙 2024-12-09 18:13:57

这是一个示例,其中等待设置变量的所有逻辑都被推迟到一个函数,然后该函数调用一个回调来执行程序需要执行的所有其他操作 - 如果您需要在执行其他操作之前加载变量,这感觉就像一个简洁的方法-ish 方式来做到这一点,因此您将变量加载与其他所有内容分开,同时仍然确保“其他所有内容”本质上是回调。

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

  });

Here's an example where all the logic for waiting until the variable is set gets deferred to a function which then invokes a callback that does everything else the program needs to do - if you need to load variables before doing anything else, this feels like a neat-ish way to do it, so you're separating the variable loading from everything else, while still ensuring 'everything else' is essentially a callback.

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

  });
薔薇婲 2024-12-09 18:13:57

使用文档上的就绪事件,而不是使用窗口加载事件。

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

当 DOM 中的所有内容都准备就绪(包括完全加载的媒体内容)时,应该会触发此操作。

Instead of using the windows load event use the ready event on the document.

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

This should fire when everything in the DOM is ready to go, including media content fully loaded.

少女的英雄梦 2024-12-09 18:13:57

更短的方法:

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

您还可以传递参数

Shorter way:

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

You can also pass arguments

烟沫凡尘 2024-12-09 18:13:57

我已经对@dnuttle的答案投了赞成票,但最终使用了以下策略:

// 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

I have upvoted @dnuttle's answer, but ended up using the following strategy:

// 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();
});

It is tested and working! ;)

Gist: https://gist.github.com/dreamyguy/f319f0b2bffb1f812cf8b7cae4abb47c

羁客 2024-12-09 18:13:57
Object.defineProperty(window, 'propertyName', {
    set: value => {
        this._value = value;
        // someAction();
    },
    get: () => this._value
});

或者即使您只是希望将此属性作为参数传递给函数并且不需要在全局对象上定义它:

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

但是,因为在您的示例中您似乎希望在创建节点时执行操作,我建议你看看MutationObservers

Object.defineProperty(window, 'propertyName', {
    set: value => {
        this._value = value;
        // someAction();
    },
    get: () => this._value
});

or even if you just want this property to be passed as an argument to a function and don't need it to be defined on a global object:

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

However, since in your example you seem to want to perform an action upon creation of a node, I would suggest you take a look at MutationObservers.

过度放纵 2024-12-09 18:13:57

我对@dnuttle 的答案进行了改编,我建议使用它。

使用 try-catch 块的优点是,如果您尝试执行的代码的任何部分失败,则整个块都会失败。我发现这很有用,因为它为你提供了一种交易;一切都完成或什么都不完成。

永远不要编写可能因外部因素而陷入无限循环的代码。如果您正在等待 ajax 请求的响应而服务器没有响应,就会发生这种情况。我认为对任何有问题的循环设置超时是一个很好的做法。

let time = 0; // Used to keep track of how long the loop runs
function waitForElement() {
  try {
    // I'm testing for an element, but this condition can be
    // any reasonable condition
    if (document.getElementById('test') === null) {
      throw 'error';
    }

    // This is where you can do something with your variable
    // document.getElementById('test').addEventListener....
    // or call a function that uses your value

  } catch (error) {
    // Loop stops executing if not successful within about 5 seconds
    if (time > 5000) {
      // I return false on failure so I can easily check for failure
      return false;
    } else {
      // Increment the time and call the function again
      time += 250;
      setTimeout(waitForElement, 250);
    }
  }
}

// Call the function after the definition, ensures that time is set
waitForElement();

I have an adaptation of the answer by @dnuttle that I would suggest using.

The advantage of using a try-catch block is that if any part of the code you are trying to execute fails, the whole block fails. I find this useful because it gives you a kind of transaction; everything or nothing gets done.

You should never write code that could end up in an endless loop due to external factors. This is exactly what would happen if you were waiting for a response from an ajax request and the server doesn't respond. I think it's good practice to have a timeout for any questionable loops.

let time = 0; // Used to keep track of how long the loop runs
function waitForElement() {
  try {
    // I'm testing for an element, but this condition can be
    // any reasonable condition
    if (document.getElementById('test') === null) {
      throw 'error';
    }

    // This is where you can do something with your variable
    // document.getElementById('test').addEventListener....
    // or call a function that uses your value

  } catch (error) {
    // Loop stops executing if not successful within about 5 seconds
    if (time > 5000) {
      // I return false on failure so I can easily check for failure
      return false;
    } else {
      // Increment the time and call the function again
      time += 250;
      setTimeout(waitForElement, 250);
    }
  }
}

// Call the function after the definition, ensures that time is set
waitForElement();
瞳孔里扚悲伤 2024-12-09 18:13:57

您可以让 Flash 在完成后调用该函数。我不确定你所说的网络服务是什么意思。我假设您有 JavaScript 代码通过 Ajax 调用 Web 服务,在这种情况下您会知道它们何时终止。在最坏的情况下,您可以执行循环 setTimeout 每隔 100 毫秒左右检查一次。

检查变量是否已定义可以只是 if (myVariable) 或更安全:if(typeof myVariable == "undefined")

You could have Flash call the function when it's done. I'm not sure what you mean by web services. I assume you have JavaScript code calling web services via Ajax, in which case you would know when they terminate. In the worst case, you could do a looping setTimeout that would check every 100 ms or so.

And the check for whether or not a variable is defined can be just if (myVariable) or safer: if(typeof myVariable == "undefined")

安稳善良 2024-12-09 18:13:57
while (typeof myVar == void(0)) {
  if ( typeof myVar != void(0)) {
        console.log(myVar);
  }
}

这利用了 typeof 运算符,如果尚未声明变量,则仅返回 undefined。应该适用于所有类型的 javascript。

while (typeof myVar == void(0)) {
  if ( typeof myVar != void(0)) {
        console.log(myVar);
  }
}

This makes use of the typeof operator which only returns undefined if variable is not declared yet. Should be applicable in every type of javascript.

離人涙 2024-12-09 18:13:57

我知道我对这个问题晚了几年:很多人都走了超时路线,如果您无法访问定义变量的代码,这可能是最简单的方法。

然而,OP表明这都是他们自己的代码。在这种情况下,我认为最好在定义变量后调度一个事件,而不是字面地等待窗口对象定义变量,以免不必要地浪费资源

定义代码

window.someVariable = 'foo';
const ev = new Event( 'someVariableDefined' );
document.dispatchEvent( ev );

监听代码

const triggerClick = () => {
    // cleanup
    document.removeEventListener( 'someVariableDefined', triggerClick, false );
    $('a.play').trigger("click");
}

if( !!window.someVariable ){
    triggerClick();
} else {
    document.addEventListener( 'someVariableDefined', triggerClick, false );
}

I know I'm a few years late to this question: A lot of people have gone the timeout route, which if you do not have access to the code that defines the variable, that is probably the easiest way to go.

However, the OP suggests that it's all their own code. In this instance, instead of literally waiting for the window object to define the variable, I think it would be better to dispatch an event once the variable is defined, to not waste resources unnecessarily

Defining code

window.someVariable = 'foo';
const ev = new Event( 'someVariableDefined' );
document.dispatchEvent( ev );

Listening code

const triggerClick = () => {
    // cleanup
    document.removeEventListener( 'someVariableDefined', triggerClick, false );
    $('a.play').trigger("click");
}

if( !!window.someVariable ){
    triggerClick();
} else {
    document.addEventListener( 'someVariableDefined', triggerClick, false );
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文