简体   繁体   English

等待一个变量存在,然后在 javascript 中做一些事情

[英]Wait for a variable to exist then do something in javascript

I have a script that will be executed before the variable it must read will be loaded..我有一个脚本,它将在加载必须读取的变量之前执行..

this is my script that will be executed first这是我将首先执行的脚本

funcThatWaits(varToWait).ready(function(){
        //callback time!!
    alert("varToBeWait is Ready!!");
});

and this is the script that will be next to be loaded这是接下来要加载的脚本

var varToWait=null;

All I want is to create a function that will wait to a variable to exist and do a callback automatically when it detects the variable already existed.(This means while the variable does not exist it will wait)我想要的只是创建一个函数,该函数将等待变量存在并在检测到变量已存在时自动执行回调。(这意味着当变量不存在时,它将等待)

Is this possible?这可能吗? my first script is quite copied on the $(document).ready() function of jquery that waits for the DOM to be fully loaded... is this possible for JS variables?我的第一个脚本完全复制在 jquery 的 $(document).ready() 函数上,它等待 DOM 完全加载......这可能用于 JS 变量吗?

If your variable comes from another function (and maybe from another scope), then you can pass a callback and provide it the variable when the second function executes the callback. 如果您的变量来自另一个函数(可能来自另一个作用域),那么您可以传递一个回调,并在第二个函数执行该回调时向其提供变量。 you don't need to wait when it will exist, but you will wait until the second script provides it for you . 您无需等待它存在的时间,但是您将等到第二个脚本为您提供它

//in the second script:

var varIWant = 'foo'

function fromSecondScript(callback){
    callback(varIWant);
}

//in the first script:

function fromFirstScript(){
    fromSecondScript(function(theVar){
        //"theVar" in this function scope is "varIWant" from the other scope
    })
}

another way to do it is to have a loader script defined beforehand to aggregate callbacks and call them once their variables are set: 另一种方法是预先定义一个加载程序脚本,以聚合回调并在设置了变量后调用它们:

var aggregator = (function(){
    var stored = {};

    return {
        //adds a callback to storage
        addCallback : function(varName,callback){
            if(!stored.hasOwnProperty(varName)){
                stored[varName] = [];
            }
            stored[varName].push(callback);
        },
        //executes stored callbacks providing them data
        execute : function(varName,data){
            if(stored.hasOwnProperty(varName)){
                for(var i=0;i<stored[varName].length;i++){
                    stored[varName][i](data)
                }
            }
        }
}());

//in the first script add callbacks. you can add any number of callbacks
aggregator.addCallback('VarExists',function(theVar){
    //do what you want when it exists
});

aggregator.addCallback('VarExists',function(theVar){
    //another callback to execute when var exists
});

//in the second script, execute the callbacks of the given name
aggregator.execute('VarExists',theVarYouWantToShare);

Intro介绍

The only way I've found is to create a fully-fledged tracking mechanism.我发现的唯一方法是创建一个成熟的跟踪机制。

The currently accepted answer does the job, but I personally like to hide implementation details a bit more.当前接受的答案可以完成这项工作,但我个人更喜欢隐藏实现细节。

Preparation准备

We'll create a class to keep track of things.我们将创建一个类来跟踪事物。

/* ChangeTracker.js */

// Mechanism to keep track of when a variable is set.
class ChangeTracker {
  constructor() {
    this._value = null;            // <- the var we're waiting for
    this._valueAlreadySet = false; // <- used to track first set
    this._singleListeners = [];    // <- used for one-off requests
    this._multiListeners = [];     // <- used for recurring requests
  }

  // Using this, you'll be notified the first time the value changes. If the
  // value has already been set, you'll be notified immediately.
  getOnce(callback) {
    if (this._valueAlreadySet) {
      callback(this._value);
    }
    else {
      this._singleListeners.push(callback);
    }
  }

  // Using this, you'll be notified every time the value changes. If the value
  // has already been set, you'll be notified immediately.
  getEveryChange(callback) {
    this._multiListeners.push(callback);
    if (this._valueAlreadySet) {
      callback(this._value);
    }
  }

  // Sets the value, then notifies those waiting for it.
  setValue(value) {
    this._value = value;
    if (!this._valueAlreadySet) {
      this._valueAlreadySet = true;

      // Notify all one-off listeners.
      const singleListeners = this._singleListeners;
      for (let i = 0; i < singleListeners.length; i++) {
        singleListeners[i](value);
      }

      // Mark for garbage collection.
      this._singleListeners = null;
    }

    // Notify all subscribers.
    for (let i = 0; i < this._multiListeners.length; i++) {
      this._multiListeners[i](value);
    }
  }
}

Data source数据源

We'll be loading a spaceship.我们将装载一艘宇宙飞船。 It will eventually have our variable, but it's asynchronous and takes long to initialise.它最终会拥有我们的变量,但它是异步的并且需要很长时间来初始化。

/* shipLoader.js */

// We will store a 1GB spaceship in here.
const spaceship = new ChangeTracker();

// Simulate a long loading process:
setTimeout(() => {
  spaceship.setValue({ name: 'Friday', color: 'Lilac' });
}, 6174);

// Player gets into a bigger spaceship:
setTimeout(() => {
  spaceship.setValue({ name: 'The Unshakeable', color: 'Blood red' });
}, 9999);

Consumer消费者

The following script wants the variable.以下脚本需要该变量。 It'll ask for it, and proceed the first time that it's set.它会要求它,并在第一次设置时继续。 Note that run order does not matter - this will work whether this code runs first or the spacehip loads first.请注意,运行顺序无关紧要 - 无论此代码先运行还是飞船先加载,这都将起作用。

/* activateHud.js */

// Receive the value when it's set, then do some processing.
spaceship.getOnce((value) => {
  console.log('Got spaceship:', value);
  // ^-> Got spaceship: { name: 'Friday', color: 'Lilac' }
});

Logger记录器

The above works fine if you care only about getting the current value.如果您只关心获取当前值,则上述方法可以正常工作。 Below we have a logger that will keep track of all future changes:下面我们有一个记录器,它将跟踪所有未来的变化:

/* logger.js */

// Log the value every time it changes.
spaceship.getEveryChange((value) => {
  const date = new Date().toLocaleString();
  console.log(`[${date}] New spaceship loaded:`, value);
  // ^-> New spaceship loaded: { name: 'Friday', color: 'Lilac' }
  //   > New spaceship loaded: { name: 'The Unshakeable', color: 'Blood red' }
});

Optimising a bit稍微优化一下

The above class will notify all getEveryChange listeners every time you set the value, even if it's the exact same value as before.每次设置值时,上面的类都会通知所有getEveryChange侦听器,即使它与以前的值完全相同。 If this is not desired, you can prevent this behaviour by adding if (this._value === value) return;如果这不是你想要的,你可以通过添加if (this._value === value) return;来防止这种行为if (this._value === value) return; to the setValue class method.setValue类方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM