2017-01-26 2 views
3

Я хочу установить интервал в http-запросе с использованием rxjs. Мне нужно отправить данные на сервер через n секунд после завершения запроса.Как запросить асинхронный интервал, используя rxjs в Angular 2

Observable.interval(10000) 
        .?(() => { 
         //request for server. return Observable 
         return this.getData(); 
        }) 
        .subscribe(() => { 
         console.log("Request done. After 10 second will be next request"); 
        }); 

UPDATE на основе .expand() предложил Марк

ngOnInit() { 
    this.getData() 
    .expand(() => Rx.Observable.timer(10 * 1000) 
     .concatMap(() => this.getData()) 
    ) 
    .subscribe(data => { 
     console.log('received new data', data); 
    }); 
} 

private getData() { 
    return Observable.timer(5000) 
    .do(() => console.log("timer")); 
} 

ответ

2

Ваш UseCase отличный случай для .expand оператора, который может рекурсивно выполнить и возвращать новые значения. См. Этот фрагмент, в котором я добавил много записей timestamp + debug, чтобы уточнить, что происходит.

function getData() { 
 
    // simulate remote call which can take some time 
 
    return Rx.Observable.of('') 
 
    .timestamp() 
 
    .do(i => console.log(`[debug] Going to fetch data from server @${i.timestamp}`)) 
 
    .map(i => 'the new JSON blob of data to use') // this would be your actual http.get call 
 
    .delay(1500) 
 
    .timestamp() 
 
    .do(i => console.log(`[debug] Data retreived from server @${i.timestamp}`)); 
 
} 
 

 
getData() 
 
    .expand(_ => Rx.Observable.of('') // we need something to delay upon 
 
    .timestamp() 
 
    .do(i => console.log(`[debug] Waiting 1sec for next getData ${i.timestamp}`)) 
 
    .delay(1000) 
 
    .concatMap(() => getData()) 
 
) 
 
    .take(5) 
 
    .subscribe(val => console.log(`New data received @${val.timestamp} : ${val.value}`))
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.3/Rx.js"></script>

поэтому изначально вы подписались на getData() и расширить свое значение рекурсивно delay для времени до получения следующего getData(). В этом подходе нет субъектов, и ваша подписка остается доступной для получения новых значений.

+0

Вопрос - это обновление. Правильно ли я понимаю? – Illorian

+0

Я не знал о '.expand()' operator .... Это выглядит интересно :), мне всегда было плохо, используя те виды автоматической обратной связи (вот почему я начал свой ответ так: «Это сложно ") – olivarra1

+0

@ olivarra1, но он работает странно – Illorian

3

я думаю, что вы хотите, чтобы запросить сервер для чего-то каждые несколько секунд. Вы можете попробовать этот путь

убедитесь, что вы импортируемого импорт {} Наблюдаемые из «rxjs/Rx», если вы не импортировать его, мы получаем наблюдаемую не найдена ошибка иногда

http://plnkr.co/edit/vMvnQW?p=preview рабочий plnkr

import {Component} from '@angular/core'; 
import {Http} from '@angular/http'; 
import 'rxjs/Rx'; 
import {Observable} from 'rxjs/Rx'; 

@Component({ 
    selector: 'app', 
    template: ` 
     <b>Angular 2 HTTP request every 5 sec RxJs Observables!</b> 
     <ul> 
     <li *ngFor="let doctor of doctors">{{doctor.name}}</li> 
     </ul> 

     ` 
}) 

export class MyApp { 
    private doctors = []; 

    constructor(http: Http) { 
    Observable.interval(5000) 
    .switchMap(() => http.get('http://jsonplaceholder.typicode.com/users/')).map((data) => data.json()) 
     .subscribe((data) => { 
      this.doctors=data; 
      console.log(data);// see console you get output every 5 sec 
     }); 
    } 
} 

см. Консоль Google для проверки. Вы будете получать новые данные каждые 5 секунд.

+0

Будет ли отменен запрос, если компонент будет уничтожен? – Illorian

+0

зависит от того, где вы вызываете его из службы или компонента. как только этот вызывающий компонент будет уничтожен, он должен отменить запрос. в противном случае вы можете отказаться от подписки на него в ngOnDestroy() hook. –

+0

мое решение работает для вас @Illorian ?? –

1

Я прочитал комментарии, которые вы вложили в этот удаленный ответ. Вы хотите отправить запрос, а через 10 секунд после получения ответа отправьте другой запрос.

Это довольно сложно, но выполним ... Я думаю, что что-то, как это должно работать:

let responseSubject = new Rx.BehaviourSubject({}); 
responseSubject 
    .delay(10000) 
    .flatMap(() => { 
     return http.get(...) 
    }) 
    .subscribe((res) => { 
     responseSubject.onNext({}); 
     // Your stuff here 
    }); 

Здесь я настройка поведения, так что я могу обратную связь, когда мы получим ответ. Затем настройте поток, который через 10 секунд запроса будет делать запрос и даст ответ.

Редактировать: Мне не хватает чего-то ... первый запрос займет 10 секунд до его запуска. Тогда я хотел бы переписать так:

let responseSubject = new Rx.ReplaySubject(1); 
responseSubject 
    .delay(10000) 
    .startWith({}) 
    .flatMap(() => { 
     return http.get(...) 
    }) 
    .subscribe((res) => { 
     responseSubject.onNext({}); 
     // Your stuff here 
    }); 
+0

Разве это не тривиальная задача? Отправить запрос на сервер по таймеру ... Моя проблема в том, что запрос может быть длинным ... – Illorian

+0

Нет, потому что не каждые 10 секунд вы хотите отправить запрос, но через 10 секунд после получения каждого ответа, правильно? Else, если каждый запрос занимает 30 секунд, у вас одновременно будет 3 запроса – olivarra1

+0

Эти виды обратной связи делают вещи сложными ...Вы отправляете запрос, но это зависит от ответа, сделанного предыдущим запросом – olivarra1

Смежные вопросы