【问题标题】:Wait for a variable to exist then do something in javascript等待一个变量存在然后在javascript中做一些事情
【发布时间】:2012-04-17 09:02:18
【问题描述】:

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

这是我将首先执行的脚本

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

这是接下来要加载的脚本

var varToWait=null;

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

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

【问题讨论】:

  • 什么样的事件定义了你等待的变量?
  • 变量如何使它成为盛大的入口?它来自ajax结果吗?还是其他功能?
  • 它只是一个在单独的js文件上执行的变量,第一个被执行的脚本在一个单独的js文件中,并且在变量之前首先加载。第二个脚本生成变量并动态生成,这就是为什么我需要知道变量是否已经存在

标签: javascript multithreading function callback


【解决方案1】:

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

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

【讨论】:

  • 我不能准备好像 jquery 这样的东西吗?哪个更简单?谢谢你的回答^^
  • 啊,谢谢...我会等待您的答复:D。我想要非常简单的代码,因为我需要多次重用第一个脚本..我已经选择了你的第一个答案(研究了 JavaScript 函数),但这并不是我真正需要的..
  • 已更新。外观不是很 jQuery,但总是做同样的工作。
  • 虽然 OP 的作者标记了这个正确的答案,但我仍然有疑问 - 在第一个脚本执行时,如果第二个脚本没有加载,那么 fromSecondScript 调用(来自第一个脚本)将失败,不是吗?因此,第二个脚本没有回调。即使是第二个例子,如果在缓存回调之前调用execute,那么什么也不会发生。我错过了什么吗?
  • 第一个例子只是为了展示如何传递一个回调并在执行期间为其提供一个值。是的,在他的情况下它会失败。第二个示例使用在两个脚本之前加载的聚合器函数。是的,如果您在添加回调之前执行,则不会发生任何事情。但 OP 只是想将变量提供给 beforehand 创建的函数。意味着在执行之前要添加一个回调。
【解决方案2】:

简介

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

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

准备

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

/* 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 类方法来防止这种行为。

【讨论】:

    猜你喜欢
    • 2011-10-09
    • 1970-01-01
    • 1970-01-01
    • 2016-09-22
    • 1970-01-01
    • 2021-06-25
    • 2014-10-17
    • 2021-08-29
    • 2020-02-02
    相关资源
    最近更新 更多