Angular2 / RXJS - handling potentially long requests

Objective: . Front-end applications allow users to select files from their local computers and send file names to the server. The server then maps these file names to files located on the server. Then the server will return a list of all matching files.

Problem: This works fine if the user selects less than a few hundred files, otherwise it may cause a long response time. I do not want to limit the number of files that the user can select, and I do not want to worry about the timeouts of http requests in the interface.

Code example:

//html on front-end to collect file information
<div>
    <input (change)="add_files($event)" type="file" multiple>
</div>

//function called from the front-end, which then calls the profile_service add_files function
//it passes along the $event object
add_files($event){

    this.profile_service.add_files($event).subscribe(
        data => console.log('request returned'),
        err => console.error(err),
        () => //update view function
    );       
}

//The following two functions are in my profile_service which is dependency injected into my componenet
//formats the event object for the eventual query
add_files(event_obj){

        let file_arr = [];
        let file_obj = event_obj.target.files;

        for(let key in file_obj){
            if (file_obj.hasOwnProperty(key)){
                file_arr.push(file_obj[key]['name'])
            }
        }

        let query_obj = {files:title_arr};

        return this.save_files(query_obj)
}

//here is where the actual request to the back-end is made
save_files(query_obj){

    let payload = JSON.stringify(query_obj);
    let headers = new Headers();

    headers.append('Content-Type', 'application/json');
    return this.http.post('https://some_url/api/1.0/collection',payload,{headers:headers})
        .map((res:Response) => res.json())
}

Possible solutions:

  • . , 25 , 25 . , ? , , .

  • , " , ". db , , db , . , , .

. angular2/observables .

+4
2

, , , , # 1. - , :

add_files(event_obj){

    let file_arr = [];
    let file_obj = event_obj.target.files;

    for(let key in file_obj){
        if (file_obj.hasOwnProperty(key)){
            file_arr.push(file_obj[key]['name'])
        }
    }

    let self = this;
    let bufferedFiles = Observable.from(file_arr)
        .bufferCount(25); //Nice round number that you could play with

    return bufferedFiles

       //concatMap will make sure that each of your requests are not executed
       //until the previous completes. Then all the data is merged into a single output
       .concatMap((arr) => {

         let payload = JSON.stringify({files: arr});
         let headers = new Headers();
         hearders.append('Content-Type', 'application/json');

         //Use defer to make sure because http.post is eager
         //this makes it only execute after subscription
         return Observable.defer(() => 
            self.post('https://some_url/api/1.0/collection',payload, {headers:headers})
       }, resp => resp.json());
}

concatMap , , , . mergeMap, , , , , , .

+3

-, .

. - https://www.npmjs.com/package/angular2-websocket - http://mmrath.com/post/websockets-with-angular2-and-spring-boot/ - http://www.html5rocks.com/de/tutorials/websockets/basics/

, , .

,

getAll(urls:any[]):Observable {
  let observables = [];
  for(var i = 0; i < items.length; i++) {
    observables.push(this.http.get(urls[i]));
  }
  return Observable.forkJoin(observables);
}

someMethod(server:string) {
  let urls = [
   '${server}/fileService?somedata=a',
   '${server}/fileService?somedata=b',
   '${server}/fileService?somedata=c'];

  this.getAll(urls).subscribe(
      (value) => processValue(val),
      (err) => processError(err),
      () => onDone());
}
0

All Articles