2

我有一个脚本将在加载它必须读取的变量之前执行..

这是我的脚本,将首先执行

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

这是接下来要加载的脚本

var varToWait=null;

我想要的只是创建一个函数,该函数将等待变量存在并在检测到变量已存在时自动执行回调。(这意味着当变量不存在时它会等待)

这可能吗?我的第一个脚本完全复制在 jquery 的 $(document).ready() 函数上,该函数等待 DOM 完全加载......这对于 JS 变量是否可行?

4

2 回答 2

2

如果您的变量来自另一个函数(并且可能来自另一个范围),那么您可以传递一个回调并在第二个函数执行回调时为其提供变量。您无需等待它何时存在,但您将等到第二个脚本为您提供它

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

另一种方法是预先定义一个加载器脚本来聚合回调并在设置变量后调用它们:

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);
于 2012-04-17T09:13:13.480 回答
0

介绍

我发现的唯一方法是创建一个成熟的跟踪机制。

当前接受的答案可以完成这项工作,但我个人更喜欢隐藏实现细节。

准备

我们将创建一个类来跟踪事物。

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

数据源

我们将装载一艘宇宙飞船。它最终会有我们的变量,但它是异步的并且需要很长时间来初始化。

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

消费者

以下脚本需要该变量。它会要求它,并在第一次设置时继续。请注意,运行顺序无关紧要 - 无论此代码先运行还是宇宙飞船先加载,这都会起作用。

/* 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.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' }
});

优化一点

每次设置值时,上面的类都会通知所有getEveryChange侦听器,即使它与以前的值完全相同。如果不希望这样做,您可以通过添加if (this._value === value) return;setValue类方法来防止这种行为。

于 2021-12-01T04:51:46.443 回答