I have an array of items, and while dragging I want to add some extra items to this array and remove the items when dropped. The items are accessed 60 times per second and I am wondering what is the performance penalty for this operation with the implementation below.
class Hello {
get constraints() {
return [...this._constraints, ...(this._extras | [])]
}
_extras: Array<number> | undefined
constructor(readonly _constraints: Array<number>) {
}
}
let hello = new Hello([1,2,3,4, 100000])
hello._extras = [5, 6, 7]
function step() {
console.log(hello.constraints)
requestAnimationFrame(step)
}
requestAnimationFrame(step)
Currently it clones the arrays each time the items is accessed, what is the penalty for this. What is a better way to code this pattern of behavior.
CodePudding user response:
Construct the constraints
array only when needed - when the _extras
change. Provide a method for its changing.
class Hello {
constraints: Array<number>;
setExtras(extras: Array<number>) {
this.constraints = [...this._constraints, ...extras];
}
_extras: Array<number> | undefined
constructor(readonly _constraints: Array<number>) {
this.constraints = _constraints;
}
}
const hello = new Hello([1, 2, 3, 4, 100000])
hello.setExtras([5, 6, 7]);
function step() {
console.log(hello.constraints)
requestAnimationFrame(step)
}
requestAnimationFrame(step)
CodePudding user response:
By using requestAnimationFrame
I'm assuming this is something that can be asynchronous, but high-priority asynchronous?
If you install rxjs into your project, after importing the rxjs used below, you can have something like...
const initialConstraints = [1,2,3,4, 100000];
const others$: BehaviorSubject<number[]> = new BehaviorSubject();
// While subcribed to, emits combined
// constraints once per time
// others$.next(numArray) is called.
const constraints$ = others$.pipe(
map(
others => !others || !others.length ? initialConstraints
: [...initialConstraints, ...others]
)
);
// While subscribes to, emits a MouseEvent
// every time the mouse is moved
const moves$ = fromEvent(document, 'mousemove');
type StepArgument = [number[], MouseEvent];
// While subscribed, emits a two element
// array each time that others$.next is
// called and/or the mouse is moved, and what
// happens next is done as part of the
// animation scheduler.
const both$: Observable<StepArgument> = scheduled(
others$.pipe(
combineLatestWith(moves$),
shareReplay(1)
),
animationFrameScheduler
);
// Now, unless anything is subscribing to an
// observable, nothing is happening. You're
// just a plumber who has set up pipes but
// nothing is running through it.
// Once called, `both$` will emit values into
// the step argument until the returned
// subscription objects's `unsubscribe`
// function is called.
function watchMouse(step: ((arg: StepArgument) => void) {
return both$.subscribe(step);
}
This allows for more flexibility later down the line, too.
Note: When both$
is subscribed to, it might not emit anything until the mouse moves because it starts listening to the mouse event stream without memory of prior mouse moves.
(caveat: example code not debugged)