介绍
我发现的唯一方法是创建一个成熟的跟踪机制。
当前接受的答案可以完成这项工作,但我个人更喜欢隐藏实现细节。
准备
我们将创建一个类来跟踪事物。
/* 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
类方法来防止这种行为。