Rxjs Gözlemci / Gözlemlenebilir + Önbellekleme + Abonelik Kullanılarak Önbelleğe Alınabilir HTTP Yanıt Verileri
Bkz. Aşağıdaki Kod
* Feragatname: Ben rxjs için yeniyim, bu yüzden gözlenebilir / gözlemci yaklaşımını kötüye kullandığımı unutmayın. Çözümüm tamamen bulduğum diğer çözümlerin bir araya gelmesi ve iyi belgelenmiş basit bir çözüm bulamamanın sonucudur. Böylece başkalarına yardım umuduyla (bulmayı isterdim gibi) tam kod çözümümü sağlıyorum.
* unutmayın, bu yaklaşım gevşek bir şekilde GoogleFirebaseObservables tabanlıdır. Ne yazık ki uygun deneyim / zaman başlık altında ne yaptığını çoğaltmak için eksikliği. Ancak aşağıdakiler, bazı önbelleklenebilir verilere eşzamansız erişim sağlamanın basit bir yoludur.
Durum : Bir 'ürün listesi' bileşeni, bir ürün listesi görüntülemekle görevlendirilir. Site, sayfada görüntülenen ürünleri 'filtreleyecek' bazı menü düğmelerine sahip tek sayfalık bir web uygulamasıdır.
Çözüm : Bileşen bir hizmet yöntemine "abone olur". Hizmet yöntemi, bileşenin abonelik geri araması yoluyla eriştiği bir dizi ürün nesnesi döndürür. Hizmet yöntemi, etkinliğini yeni oluşturulan bir Gözlemciye sarar ve gözlemciyi döndürür. Bu gözlemcinin içinde, önbelleğe alınmış verileri arar ve aboneye (bileşene) geri aktarır ve geri döner. Aksi takdirde, verileri almak için bir http çağrısı yapar, yanıta abone olur, burada verileri işleyebilir (örneğin verileri kendi modelinize eşleyebilirsiniz) ve ardından verileri aboneye geri aktarabilirsiniz.
Kod
Ürün-list.component.ts
import { Component, OnInit, Input } from '@angular/core';
import { ProductService } from '../../../services/product.service';
import { Product, ProductResponse } from '../../../models/Product';
@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.scss']
})
export class ProductListComponent implements OnInit {
products: Product[];
constructor(
private productService: ProductService
) { }
ngOnInit() {
console.log('product-list init...');
this.productService.getProducts().subscribe(products => {
console.log('product-list received updated products');
this.products = products;
});
}
}
product.service.ts
import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Observable, Observer } from 'rxjs';
import 'rxjs/add/operator/map';
import { Product, ProductResponse } from '../models/Product';
@Injectable()
export class ProductService {
products: Product[];
constructor(
private http:Http
) {
console.log('product service init. calling http to get products...');
}
getProducts():Observable<Product[]>{
//wrap getProducts around an Observable to make it async.
let productsObservable$ = Observable.create((observer: Observer<Product[]>) => {
//return products if it was previously fetched
if(this.products){
console.log('## returning existing products');
observer.next(this.products);
return observer.complete();
}
//Fetch products from REST API
console.log('** products do not yet exist; fetching from rest api...');
let headers = new Headers();
this.http.get('http://localhost:3000/products/', {headers: headers})
.map(res => res.json()).subscribe((response:ProductResponse) => {
console.log('productResponse: ', response);
let productlist = Product.fromJsonList(response.products); //convert service observable to product[]
this.products = productlist;
observer.next(productlist);
});
});
return productsObservable$;
}
}
product.ts (model)
export interface ProductResponse {
success: boolean;
msg: string;
products: Product[];
}
export class Product {
product_id: number;
sku: string;
product_title: string;
..etc...
constructor(product_id: number,
sku: string,
product_title: string,
...etc...
){
//typescript will not autoassign the formal parameters to related properties for exported classes.
this.product_id = product_id;
this.sku = sku;
this.product_title = product_title;
...etc...
}
//Class method to convert products within http response to pure array of Product objects.
//Caller: product.service:getProducts()
static fromJsonList(products:any): Product[] {
let mappedArray = products.map(Product.fromJson);
return mappedArray;
}
//add more parameters depending on your database entries and constructor
static fromJson({
product_id,
sku,
product_title,
...etc...
}): Product {
return new Product(
product_id,
sku,
product_title,
...etc...
);
}
}
Sayfayı Chrome'a yüklediğimde gördüğüm çıktıdan bir örnek. İlk yükte, ürünlerin http'den getirildiğini unutmayın (3000 numaralı bağlantı noktasında yerel olarak çalışan düğüm dinlenme hizmetime çağrı yapın). Daha sonra ürünlerin 'filtrelenmiş' görünümüne gitmek için tıkladığımda, ürünler önbellekte bulunur.
Chrome Günlüğüm (konsol):
core.es5.js:2925 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
app.component.ts:19 app.component url: /products
product.service.ts:15 product service init. calling http to get products...
product-list.component.ts:18 product-list init...
product.service.ts:29 ** products do not yet exist; fetching from rest api...
product.service.ts:33 productResponse: {success: true, msg: "Products found", products: Array(23)}
product-list.component.ts:20 product-list received updated products
... [ürünleri filtrelemek için bir menü düğmesini tıklattı] ...
app.component.ts:19 app.component url: /products/chocolatechip
product-list.component.ts:18 product-list init...
product.service.ts:24 ## returning existing products
product-list.component.ts:20 product-list received updated products
Sonuç: Bu, şu ana kadar önbelleğe alınabilen http yanıt verilerini uygulamak için bulduğum en basit yöntem. Açısal uygulamamda, ürünlerin farklı bir görünümüne her gittiğimde, ürün listesi bileşeni yeniden yüklenir. ProductService paylaşılan bir örnek gibi görünüyor, bu nedenle ProductService içindeki 'products: Product []' yerel önbelleği gezinme sırasında korunur ve sonraki "GetProducts ()" çağrıları önbelleğe alınan değeri döndürür. Son bir not, 'bellek sızıntılarını' önlemek için tamamlandığında gözlemlenebilirlerin / aboneliklerin nasıl kapatılması gerektiği hakkında yorumları okudum. Bunu buraya dahil etmedim, ama akılda tutulması gereken bir şey.