Home > Software engineering >  How to optimize for accessing an array of items plus some extra items in and out
How to optimize for accessing an array of items plus some extra items in and out

Time:10-16

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)

  • Related