如何每隔一段时间发出HTTP请求?
How to make HTTP request at an interval?
我对 angular 和 rxjs 还很陌生。
我正在尝试创建一个 angular2 应用程序,它从静态服务的文本文件(在服务器本地)获取一些数据,我想在固定时间使用 Angular2 的 http 提供程序和 rxjs 的映射检索并映射到 Datamodel interval(5000)
。反映对提供的 txt 文件的任何更改。
使用 rxjs 4.x 我知道你可以使用 Observable.interval(5000)
来完成这项工作,但它似乎不存在于 rxjs 5 中。
我的解决方法目前使用 <meta http-equiv="refresh" content="5" >
刷新整个应用程序,这会重新加载整个页面,从而重新加载数据。
所以我真正想要的是使用可观察对象执行此操作的某种方法,也许可以检查是否发生了任何更改。或者只是重新加载数据。
任何帮助或other/better方式将不胜感激。
我目前拥有的:
@Injectable()
export class DataService {
constructor(private http:Http){}
getData(url) {
return this.http.get(url)
.map(res => {
return res.text();
})
.map(res => {
return res.split("\n");
})
.map(res => {
var dataModels: DataModel[] = [];
res.forEach(str => {
var s = str.split(",");
if(s[0] !== "") {
dataModels.push(new DataModel(s[0], parseInt(s[1]), parseInt(s[2])));
}
});
return dataModels;
})
}
}
@Component({
selector: 'my-app',
template: `Some html to display the data`,
providers: [DataService],
export class AppComponent {
data:DataModel[];
constructor(dataService:DataService) {}
ngOnInit() {
this.dataService.getData('url').subscribe(
res => {
this.data= res;
},
err => console.log(err),
() => console.log("Data received")
);
}
}
依赖关系:package.json
"dependencies": {
"angular2": "^2.0.0-beta.3",
"bootstrap": "^4.0.0-alpha.2",
"es6-promise": "^3.0.2",
"es6-shim": "^0.33.13",
"jquery": "^2.2.0",
"reflect-metadata": "^0.1.2",
"rxjs": "^5.0.0-beta.0",
"systemjs": "^0.19.20",
"zone.js": "^0.5.11"
},
"devDependencies": {
"typescript": "^1.7.5"
}
index.html 进口:
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>
您可以在 Angular2 中使用 Observable
的 interval
方法。
import {Component,Input} from 'angular2/core';
import {Observable} from 'rxjs/Rx';
@Component({
selector: 'my-app',
template: `
<div>
{{message}}
</div>
`
})
export class AppComponent {
constructor() {
Observable.interval(500)
.take(10).map((x) => x+1)
.subscribe((x) => {
this.message = x;
}):
}
}
这是相应的 plunkr 描述:https://plnkr.co/edit/pVMEbbGSzMwSBS4XEXJI?p=preview.
基于此,您可以插入您的 HTTP 请求:
initializePolling() {
return Observable
.interval(60000)
.flatMap(() => {
return this.dataService.getData('url'));
});
}
对于带有 rxjs@5.0.0(回答时的 beta.6)的 TypeScript(回答时为 1.8.10)/angular2(回答时为 rc1),您需要使用 IntervalObservable
它扩展了 Observable
class
import {IntervalObservable} from 'rxjs/observable/IntervalObservable'
IntervalObservable.create(5000).take(10).map((x) => x + 1)
由于 rxjs/observable 最近的变化,我认为这个答案不再有效
您现在必须使用 IntervalObservable。
https://github.com/ReactiveX/rxjs/blob/master/src/observable/IntervalObservable.ts
import { IntervalObservable } from 'rxjs/observable/IntervalObservable';
@Component({
...
})
export class AppComponent {
n: number = 0;
constructor() {
IntervalObservable.create(1000).subscribe(n => this.n = n);
}
}
正如@Adam 和@Ploppy 所提到的,Observable.interval() 现在 已弃用 不是创建此类可观察对象的首选方式。执行此操作的首选方法是通过 IntervalObservable 或 TimerObservable。
[目前在 Typscript 2.5.2,rxjs 5.4.3,Angular 4.0.0]
我想在此答案中添加一些用法,以展示我在 Angular 2 框架中找到的最佳方法。
首先是您的服务(通过“ng g service MyExample”命令在 angular cli 中创建)。假设服务是 RESTful(http get request returns a json):
我的-example.service.ts
import { Injectable } from '@angular/core';
import { Http, Response} from "@angular/http";
import { MyDataModel } from "./my-data-model";
import { Observable } from "rxjs";
import 'rxjs/Rx';
@Injectable()
export class MyExampleService {
private url = 'http://localhost:3000'; // full uri of the service to consume here
constructor(private http: Http) { }
get(): Observable<MyDataModel>{
return this.http
.get(this.url)
.map((res: Response) => res.json());
}
}
*** 查看 Angular 5 ***
服务的底部更新
现在你的组件代码 ('ng g component MyExample'):
我的-example.component.ts:
import { Component, OnDestroy, OnInit } from '@angular/core';
import { MyDataModel } from "../my-data-model";
import { MyExampleService } from "../my-example.service";
import { Observable } from "rxjs";
import { IntervalObservable } from "rxjs/observable/IntervalObservable";
import 'rxjs/add/operator/takeWhile';
@Component({
selector: 'app-my-example',
templateUrl: './my-example.component.html',
styleUrls: ['./my-example.component.css']
})
export class MyExampleComponent implements OnInit, OnDestroy {
private data: MyDataModel;
private display: boolean; // whether to display info in the component
// use *ngIf="display" in your html to take
// advantage of this
private alive: boolean; // used to unsubscribe from the IntervalObservable
// when OnDestroy is called.
constructor(private myExampleService: MyExampleService) {
this.display = false;
this.alive = true;
}
ngOnInit() {
// get our data immediately when the component inits
this.myExampleService.get()
.first() // only gets fired once
.subscribe((data) => {
this.data = data;
this.display = true;
});
// get our data every subsequent 10 seconds
IntervalObservable.create(10000)
.takeWhile(() => this.alive) // only fires when component is alive
.subscribe(() => {
this.myExampleService.get()
.subscribe(data => {
this.data = data;
});
});
}
ngOnDestroy(){
this.alive = false; // switches your IntervalObservable off
}
}
===编辑===
更新了组件 ts 代码以通过 TimerObservable 整合订阅:
import { Component, OnDestroy, OnInit } from '@angular/core';
import { MyDataModel } from "../my-data-model";
import { MyExampleService } from "../my-example.service";
import { Observable } from "rxjs";
import { TimerObservable } from "rxjs/observable/TimerObservable";
import 'rxjs/add/operator/takeWhile';
@Component({
selector: 'app-my-example',
templateUrl: './my-example.component.html',
styleUrls: ['./my-example.component.css']
})
export class MyExampleComponent implements OnInit, OnDestroy {
private data: MyDataModel;
private display: boolean; // whether to display info in the component
// use *ngIf="display" in your html to take
// advantage of this
private alive: boolean; // used to unsubscribe from the TimerObservable
// when OnDestroy is called.
private interval: number;
constructor(private myExampleService: MyExampleService) {
this.display = false;
this.alive = true;
this.interval = 10000;
}
ngOnInit() {
TimerObservable.create(0, this.interval)
.takeWhile(() => this.alive)
.subscribe(() => {
this.myExampleService.get()
.subscribe((data) => {
this.data = data;
if(!this.display){
this.display = true;
}
});
});
}
ngOnDestroy(){
this.alive = false; // switches your TimerObservable off
}
}
===编辑===
my-example-service.ts(使用 HttpClient a la Angular 5):
import { Injectable } from '@angular/core';
import { HttpClient} from "@angular/common/http";
import { MyDataModel } from "./my-data-model";
import { Observable } from "rxjs";
import 'rxjs/Rx';
@Injectable()
export class MyExampleService {
private url = 'http://localhost:3000'; // full uri of the service to consume here
constructor(private http: HttpClient) { }
get(): Observable<MyDataModel>{
return this.http
.get<MyDataModel>(this.url);
}
}
注意更改为使用 HttpClient 而不是 Http(在 angular5 中已弃用)和 get 方法,该方法允许将响应解析到我们的数据模型中,而无需使用 rxjs .map() 运算符。虽然 angular5 的服务发生变化,但组件代码保持不变。
这可以通过 switchMap
轻松完成
Observable.timer(0, 5000)
.switchMap((t) =>
this.http.get(...).pipe(
catchError(...)
)
)
.subscribe(...)
Disaclaimer: this was originaly an edit for another answer, but contains too many changes.
这可以通过 switchMap
轻松完成:
Observable.timer(0, 5000)
.switchMap(() => this.http.get(...).pipe(...)
.subscribe(...)
或者在 RxJS 6 语法中:
import { timer } from 'rxjs';
import { switchMap } from 'rxjs/operators';
timer(0, 5000) // repeats every 5 seconds
.pipe(switchMap(() => this.http.get(...).pipe(...))
.subscribe(...);
您甚至可以使用 interval
而不是 timer
:
import { interval } from 'rxjs';
import { switchMap } from 'rxjs/operators';
interval(5000) // repeats every 5 seconds
.pipe(switchMap(() => this.http.get(...).pipe(...))
.subscribe(...);
我对 angular 和 rxjs 还很陌生。
我正在尝试创建一个 angular2 应用程序,它从静态服务的文本文件(在服务器本地)获取一些数据,我想在固定时间使用 Angular2 的 http 提供程序和 rxjs 的映射检索并映射到 Datamodel interval(5000)
。反映对提供的 txt 文件的任何更改。
使用 rxjs 4.x 我知道你可以使用 Observable.interval(5000)
来完成这项工作,但它似乎不存在于 rxjs 5 中。
我的解决方法目前使用 <meta http-equiv="refresh" content="5" >
刷新整个应用程序,这会重新加载整个页面,从而重新加载数据。
所以我真正想要的是使用可观察对象执行此操作的某种方法,也许可以检查是否发生了任何更改。或者只是重新加载数据。
任何帮助或other/better方式将不胜感激。
我目前拥有的:
@Injectable()
export class DataService {
constructor(private http:Http){}
getData(url) {
return this.http.get(url)
.map(res => {
return res.text();
})
.map(res => {
return res.split("\n");
})
.map(res => {
var dataModels: DataModel[] = [];
res.forEach(str => {
var s = str.split(",");
if(s[0] !== "") {
dataModels.push(new DataModel(s[0], parseInt(s[1]), parseInt(s[2])));
}
});
return dataModels;
})
}
}
@Component({
selector: 'my-app',
template: `Some html to display the data`,
providers: [DataService],
export class AppComponent {
data:DataModel[];
constructor(dataService:DataService) {}
ngOnInit() {
this.dataService.getData('url').subscribe(
res => {
this.data= res;
},
err => console.log(err),
() => console.log("Data received")
);
}
}
依赖关系:package.json
"dependencies": {
"angular2": "^2.0.0-beta.3",
"bootstrap": "^4.0.0-alpha.2",
"es6-promise": "^3.0.2",
"es6-shim": "^0.33.13",
"jquery": "^2.2.0",
"reflect-metadata": "^0.1.2",
"rxjs": "^5.0.0-beta.0",
"systemjs": "^0.19.20",
"zone.js": "^0.5.11"
},
"devDependencies": {
"typescript": "^1.7.5"
}
index.html 进口:
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>
您可以在 Angular2 中使用 Observable
的 interval
方法。
import {Component,Input} from 'angular2/core';
import {Observable} from 'rxjs/Rx';
@Component({
selector: 'my-app',
template: `
<div>
{{message}}
</div>
`
})
export class AppComponent {
constructor() {
Observable.interval(500)
.take(10).map((x) => x+1)
.subscribe((x) => {
this.message = x;
}):
}
}
这是相应的 plunkr 描述:https://plnkr.co/edit/pVMEbbGSzMwSBS4XEXJI?p=preview.
基于此,您可以插入您的 HTTP 请求:
initializePolling() {
return Observable
.interval(60000)
.flatMap(() => {
return this.dataService.getData('url'));
});
}
对于带有 rxjs@5.0.0(回答时的 beta.6)的 TypeScript(回答时为 1.8.10)/angular2(回答时为 rc1),您需要使用 IntervalObservable
它扩展了 Observable
class
import {IntervalObservable} from 'rxjs/observable/IntervalObservable'
IntervalObservable.create(5000).take(10).map((x) => x + 1)
由于 rxjs/observable 最近的变化,我认为这个答案不再有效 您现在必须使用 IntervalObservable。
https://github.com/ReactiveX/rxjs/blob/master/src/observable/IntervalObservable.ts
import { IntervalObservable } from 'rxjs/observable/IntervalObservable';
@Component({
...
})
export class AppComponent {
n: number = 0;
constructor() {
IntervalObservable.create(1000).subscribe(n => this.n = n);
}
}
正如@Adam 和@Ploppy 所提到的,Observable.interval() 现在 已弃用 不是创建此类可观察对象的首选方式。执行此操作的首选方法是通过 IntervalObservable 或 TimerObservable。
[目前在 Typscript 2.5.2,rxjs 5.4.3,Angular 4.0.0]
我想在此答案中添加一些用法,以展示我在 Angular 2 框架中找到的最佳方法。
首先是您的服务(通过“ng g service MyExample”命令在 angular cli 中创建)。假设服务是 RESTful(http get request returns a json):
我的-example.service.ts
import { Injectable } from '@angular/core';
import { Http, Response} from "@angular/http";
import { MyDataModel } from "./my-data-model";
import { Observable } from "rxjs";
import 'rxjs/Rx';
@Injectable()
export class MyExampleService {
private url = 'http://localhost:3000'; // full uri of the service to consume here
constructor(private http: Http) { }
get(): Observable<MyDataModel>{
return this.http
.get(this.url)
.map((res: Response) => res.json());
}
}
*** 查看 Angular 5 ***
服务的底部更新现在你的组件代码 ('ng g component MyExample'):
我的-example.component.ts:
import { Component, OnDestroy, OnInit } from '@angular/core';
import { MyDataModel } from "../my-data-model";
import { MyExampleService } from "../my-example.service";
import { Observable } from "rxjs";
import { IntervalObservable } from "rxjs/observable/IntervalObservable";
import 'rxjs/add/operator/takeWhile';
@Component({
selector: 'app-my-example',
templateUrl: './my-example.component.html',
styleUrls: ['./my-example.component.css']
})
export class MyExampleComponent implements OnInit, OnDestroy {
private data: MyDataModel;
private display: boolean; // whether to display info in the component
// use *ngIf="display" in your html to take
// advantage of this
private alive: boolean; // used to unsubscribe from the IntervalObservable
// when OnDestroy is called.
constructor(private myExampleService: MyExampleService) {
this.display = false;
this.alive = true;
}
ngOnInit() {
// get our data immediately when the component inits
this.myExampleService.get()
.first() // only gets fired once
.subscribe((data) => {
this.data = data;
this.display = true;
});
// get our data every subsequent 10 seconds
IntervalObservable.create(10000)
.takeWhile(() => this.alive) // only fires when component is alive
.subscribe(() => {
this.myExampleService.get()
.subscribe(data => {
this.data = data;
});
});
}
ngOnDestroy(){
this.alive = false; // switches your IntervalObservable off
}
}
===编辑===
更新了组件 ts 代码以通过 TimerObservable 整合订阅:
import { Component, OnDestroy, OnInit } from '@angular/core';
import { MyDataModel } from "../my-data-model";
import { MyExampleService } from "../my-example.service";
import { Observable } from "rxjs";
import { TimerObservable } from "rxjs/observable/TimerObservable";
import 'rxjs/add/operator/takeWhile';
@Component({
selector: 'app-my-example',
templateUrl: './my-example.component.html',
styleUrls: ['./my-example.component.css']
})
export class MyExampleComponent implements OnInit, OnDestroy {
private data: MyDataModel;
private display: boolean; // whether to display info in the component
// use *ngIf="display" in your html to take
// advantage of this
private alive: boolean; // used to unsubscribe from the TimerObservable
// when OnDestroy is called.
private interval: number;
constructor(private myExampleService: MyExampleService) {
this.display = false;
this.alive = true;
this.interval = 10000;
}
ngOnInit() {
TimerObservable.create(0, this.interval)
.takeWhile(() => this.alive)
.subscribe(() => {
this.myExampleService.get()
.subscribe((data) => {
this.data = data;
if(!this.display){
this.display = true;
}
});
});
}
ngOnDestroy(){
this.alive = false; // switches your TimerObservable off
}
}
===编辑===
my-example-service.ts(使用 HttpClient a la Angular 5):
import { Injectable } from '@angular/core';
import { HttpClient} from "@angular/common/http";
import { MyDataModel } from "./my-data-model";
import { Observable } from "rxjs";
import 'rxjs/Rx';
@Injectable()
export class MyExampleService {
private url = 'http://localhost:3000'; // full uri of the service to consume here
constructor(private http: HttpClient) { }
get(): Observable<MyDataModel>{
return this.http
.get<MyDataModel>(this.url);
}
}
注意更改为使用 HttpClient 而不是 Http(在 angular5 中已弃用)和 get 方法,该方法允许将响应解析到我们的数据模型中,而无需使用 rxjs .map() 运算符。虽然 angular5 的服务发生变化,但组件代码保持不变。
这可以通过 switchMap
Observable.timer(0, 5000)
.switchMap((t) =>
this.http.get(...).pipe(
catchError(...)
)
)
.subscribe(...)
Disaclaimer: this was originaly an edit for another answer, but contains too many changes.
这可以通过 switchMap
轻松完成:
Observable.timer(0, 5000)
.switchMap(() => this.http.get(...).pipe(...)
.subscribe(...)
或者在 RxJS 6 语法中:
import { timer } from 'rxjs';
import { switchMap } from 'rxjs/operators';
timer(0, 5000) // repeats every 5 seconds
.pipe(switchMap(() => this.http.get(...).pipe(...))
.subscribe(...);
您甚至可以使用 interval
而不是 timer
:
import { interval } from 'rxjs';
import { switchMap } from 'rxjs/operators';
interval(5000) // repeats every 5 seconds
.pipe(switchMap(() => this.http.get(...).pipe(...))
.subscribe(...);