I try to understand how i can debounce a "set" trap in javascript proxy.
function debounce(func, wait, immediate = false) {
let timeout = null;
return function(...args) {
let later = () => {
timeout = null;
if (!immediate) {
func.apply(this, args);
}
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (immediate && !timeout) {
func.apply(this, args);
}
};
}
const data = {
p1: false,
p2: true,
p3: false,
p4: true
};
const caller = debounce(() => {
console.log("data object updated", data);
}, 100);
// catch setting of values
const obj = new Proxy(data, {
set(target, prop, value, receiver) {
// how to debounce this
// with debounce i mean:
// waiting for all properties to be set
// this does not mean that all props are set
// e.g. just 2 of the 4 props could be set
// feedback
console.log(`Set ${prop}=${value}`);
caller();
// handle the setting stuff
return Reflect.set(target, prop, value, receiver);
}
});
// happens asynchron somwhere else in the code
// set all props to new value
Object.keys(obj).forEach((key) => {
obj[key] = false;
});
setTimeout(() => {
// simluate setting of not all props
Object.keys(obj).slice(1, 3).forEach((key) => {
obj[key] = true;
});
}, 1000);
The problem is, not all properties are set, which means you can't rely on the number of properties/keys to wait for. E.g. Sometimes are just 2 set, sometimes the whole object is set to new values/updated.
How can i debounce the setting without a delay?
Is there somehow a "operation" that tells me that all object keys are setted to new values? Dont know how exactly to phrase this.
I simple want to debounce the set trap, and wait for all values to be setted before executing something else.
Is there somehow a "operation" that tells me that all object keys are setted to new values?
No, there is no such thing. Code just goes on the execute, it does not know (or even keep track of) when it is "done". You just have a sequence of property assignments. Grouping them into subsequences that are "complete" before something else happens is totally arbitrary.
Your code with the delay appears to work just fine. You can make the delay shorter arbitrarily, use setTimeout(…, 0)
or also a microtask (with queueMicrotask(…)
) instead:
function debounce(func) {
let active = false;
const later = () => {
active = false;
func();
};
return () => {
if (active) return;
active = true;
queueMicrotask(later);
};
}