Make synchronous code asynchronous to process large array and emit completion percentage

Viewed 129

This doesn't seem like the correct way to do this, but it does work. Is there a "rxjs" way to make synchronous code into asynchronous code so that my observer can return before I start processing the data? The only way I could think of doing this was to put the process within a Promise.

@Component({})
export class MyClass {
  public processData() {
    const sub = new BehaviorSubject<number>(0)
    new Promise(() => {
      let c = 0
      let completionPercentage = 0
      for (let x = 0; x < width; x++) {
        for (let y = 0; y < height; y++, c++) {
          // Do some calculations
          // Then compute completion percentage
          sub.next(completionPercentage)
        }
      }
    })
    return sub.asObservable()
  }
}
1 Answers

First of all, you of course should not do that... and move calculations to BE or service worker.

But if you do -- you should use setTimeout/setInterval not to freeze your UI. You do iteration, than let Angular to detect changes and then call another iteration.

@Component({
  selector: 'my-app',
  // Most of time browser is busy, though you can click button and see that UI somehow responds
  template: '<button (click)="x = x + 1">test me</button>{{x}}<div *ngFor="let r of results">{{r}}</div>',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
  executor = new Executor();
  results = [];
  x = 0;

  ngOnInit(){
    this.executor.subject.subscribe(value => {
      this.results.push(value);
    })
    this.executor.run();
  }

}

class Executor {
  currentRun = 0;
  maxRuns = 1000;
  subject = new Subject();

  run() {
      const r = this.multiply(this.currentRun, this.currentRun);

      this.subject.next(r);
      this.currentRun++;

      if (this.currentRun < this.maxRuns) {
        setTimeout(() => this.run());
      }
  }

   multiply(a, b) {
     const t = new Date().getTime();
     let r = 0;
     for (let i = 0; i < a + 20000; i++) {
       for (let j = 0; j < b + 30000; j++) {
         r++;
       }
     }
     console.log('spent: ' + (new Date().getTime() - t), a, b); // for this time browser is frozen ~ 200-300 ms
     return r;
   }
}
Related