আরএক্সজেএস 5 এ অ্যাংুলার এইচটিপি নেটওয়ার্ক কল ফলাফল ভাগ করার সঠিক উপায় কী?


303

এইচটিটিপি ব্যবহার করে আমরা একটি পদ্ধতি কল করি যা একটি নেটওয়ার্ক কল করে এবং একটি HTTP পর্যবেক্ষণযোগ্য ফেরত দেয়:

getCustomer() {
    return this.http.get('/someUrl').map(res => res.json());
}

যদি আমরা এটি পর্যবেক্ষণযোগ্য করে নিই এবং এটিতে একাধিক গ্রাহককে যুক্ত করি:

let network$ = getCustomer();

let subscriber1 = network$.subscribe(...);
let subscriber2 = network$.subscribe(...);

আমরা কী করতে চাই তা নিশ্চিত করা যায় যে এটি একাধিক নেটওয়ার্ক অনুরোধের কারণ নয়।

এটি একটি অস্বাভাবিক দৃশ্যের মতো মনে হতে পারে তবে এটি আসলে বেশ সাধারণ: উদাহরণস্বরূপ যদি কলার একটি ত্রুটি বার্তা প্রদর্শন করার জন্য পর্যবেক্ষকটির কাছে সাবস্ক্রাইব করে এবং অ্যাসিঙ্ক পাইপ ব্যবহার করে এটি টেম্পলেটে পৌঁছে দেয় তবে আমাদের ইতিমধ্যে দু'জন গ্রাহক রয়েছে।

আরএক্সজেএস 5 এ করার সঠিক উপায়টি কী?

যথা, এটি ভাল কাজ করে বলে মনে হচ্ছে:

getCustomer() {
    return this.http.get('/someUrl').map(res => res.json()).share();
}

তবে এটি কি আরএক্সজেএস 5-এ করার এই অহঙ্কারী পদ্ধতি, বা এর পরিবর্তে আমাদের আরও কিছু করা উচিত?

দ্রষ্টব্য: নতুন কৌণিক 5 অনুসারে HttpClient, .map(res => res.json())সমস্ত উদাহরণের অংশটি এখন অকেজো, কারণ জেএসএনের ফলাফলটি এখন ডিফল্টরূপে ধরে নেওয়া হয়েছে।


1
> শেয়ার প্রকাশের জন্য অভিন্ন ()। রেফকাউন্ট ()। আসলে তা না। নিম্নলিখিত আলোচনাটি দেখুন: github.com/ReactiveX/rxjs/issues/1363
খ্রিস্টান

1
সম্পাদিত প্রশ্ন, ইস্যু অনুসারে কোডটিতে
বিশ্ববিদ্যালয়

আমি মনে করি 'এটি নির্ভর করে'। তবে আপনি যে কলগুলিতে স্থানীয়ভাবে ডেটা ক্যাশে করতে পারবেন না তার জন্য প্যারামিটারগুলি পরিবর্তন / সংমিশ্রণের কারণে এটি বোধগম্য হতে পারে না sha শেয়ার () একেবারে সঠিক জিনিস বলে মনে হয়। তবে আপনি যদি স্থানীয়ভাবে জিনিসগুলিকে ক্যাশে করতে পারেন তবে রিপ্লেসউজব্যাক্ট / বিহেভিয়ারসুবজেক্ট সম্পর্কিত অন্যান্য উত্তরগুলিও ভাল সমাধান।
জিমবি

আমি মনে করি কেবল আমাদের ডেটা ক্যাশে করার প্রয়োজন নেই, আমাদের ক্যাশে থাকা ডেটা আপডেট / সংশোধন করা দরকার। এটি একটি সাধারণ ঘটনা। উদাহরণস্বরূপ, আমি ক্যাশেড মডেলটিতে কোনও নতুন ক্ষেত্র যুক্ত করতে চাইলে বা ক্ষেত্রের মান আপডেট করতে চাই। হয়তো করে Singleton DataCacheService সঙ্গে টি ককটেলের পদ্ধতি একটি ভাল উপায় কি? ভালো লেগেছে দোকান এর Redux । আপনি কি মনে করেন?
স্লাইডশোপ 2

আপনি কেবল এনজিএক্স-ক্যাশেবল ব্যবহার করতে পারেন ! এটি আপনার দৃশ্যের সাথে আরও ভাল মানায়। নীচে আমার উত্তরটি উল্লেখ করুন
তুষার ওয়ালজাদে

উত্তর:


231

ডেটা ক্যাশে করুন এবং উপলভ্য থাকলে তা ক্যাচ করুন, অন্যথায় এইচটিটিপি অনুরোধ করুন।

import {Injectable} from '@angular/core';
import {Http, Headers} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/of'; //proper way to import the 'of' operator
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/map';
import {Data} from './data';

@Injectable()
export class DataService {
  private url: string = 'https://cors-test.appspot.com/test';

  private data: Data;
  private observable: Observable<any>;

  constructor(private http: Http) {}

  getData() {
    if(this.data) {
      // if `data` is available just return it as `Observable`
      return Observable.of(this.data); 
    } else if(this.observable) {
      // if `this.observable` is set then the request is in progress
      // return the `Observable` for the ongoing request
      return this.observable;
    } else {
      // example header (not necessary)
      let headers = new Headers();
      headers.append('Content-Type', 'application/json');
      // create the request, store the `Observable` for subsequent subscribers
      this.observable = this.http.get(this.url, {
        headers: headers
      })
      .map(response =>  {
        // when the cached data is available we don't need the `Observable` reference anymore
        this.observable = null;

        if(response.status == 400) {
          return "FAILURE";
        } else if(response.status == 200) {
          this.data = new Data(response.json());
          return this.data;
        }
        // make it shared so more than one subscriber can get the result
      })
      .share();
      return this.observable;
    }
  }
}

চূড়ান্ত উদাহরণ

এই নিবন্ধটি https://blog.thoughtram.io/angular/2018/03/05/advanced-caching-with-rxjs.html কীভাবে ক্যাশে করা যায় তার একটি দুর্দান্ত ব্যাখ্যা shareReplay


3
do()বিপরীতে map()ঘটনাটি পরিবর্তন করে না। আপনি map()পাশাপাশি ব্যবহার করতে পারেন তবে তারপরে আপনাকে কলব্যাকের শেষে সঠিক মানটি ফিরে আসার বিষয়টি নিশ্চিত করতে হয়েছিল।
গন্টার জ্যাচবাউয়ার

3
যদি কল-সাইটের যে .subscribe()মানটির প্রয়োজন হয় না তবে আপনি এটি করতে পারেন এমন মানটির কারণ এটি ঠিক পেতে পারে null(কী this.extractDataপ্রত্যাবর্তন করে তার উপর নির্ভর করে ), তবে আইএমএইচও এটি কোডের উদ্দেশ্যটি ভালভাবে প্রকাশ করে না।
গন্টার জ্যাচবাউয়ার

2
যখন this.extraDataশেষ হয় extraData() { if(foo) { doSomething();}}অন্যথায় সর্বশেষ প্রকাশের ফলাফলটি ফিরে আসে যা আপনি যা চান তা নাও হতে পারে।
গন্টার জ্যাচবাউর

9
@ গন্টার, কোডটির জন্য আপনাকে ধন্যবাদ, এটি কাজ করে। তবে, আপনি কেন ডেটা এবং পর্যবেক্ষণযোগ্য আলাদাভাবে রাখছেন তা বোঝার চেষ্টা করছি। আপনি কি কেবলমাত্র পর্যবেক্ষণযোগ্য <ডেটা> কে এইভাবে ক্যাশে রেখে কার্যকরভাবে একই প্রভাব অর্জন করতে পারবেন না? if (this.observable) { return this.observable; } else { this.observable = this.http.get(url) .map(res => res.json().data); return this.observable; }
জুলাই.টেক

3
@ হারলিনকৌর এটি শক্তিশালী ধরণের চেকিং এবং স্বতঃসম্পূর্ণতা পেতে, প্রাপ্ত জেএসওএনকে deserialized করা একটি শ্রেণি। এটি ব্যবহার করার দরকার নেই, তবে এটি সাধারণ।
গন্টার জ্যাচবাউয়ার

44

ক্রিশ্চিয়ানের পরামর্শ অনুসারে, এইচটিটিপি পর্যবেক্ষণযোগ্যদের পক্ষে এটি ভালভাবে কাজ করে, এটি কেবল একবার নির্গত হয় এবং তারপরে তারা সম্পূর্ণ করে:

getCustomer() {
    return this.http.get('/someUrl')
        .map(res => res.json()).publishLast().refCount();
}

এই পদ্ধতির ব্যবহারে বেশ কয়েকটি সমস্যা রয়েছে - প্রত্যাবর্তনযোগ্য পর্যবেক্ষণযোগ্য বাতিল বা পুনরায় চেষ্টা করা যাবে না। এটি আপনার জন্য সমস্যা নাও হতে পারে তবে এটি আবারও হতে পারে। যদি এটি কোনও সমস্যা হয় তবে shareঅপারেটরটি একটি যুক্তিসঙ্গত পছন্দ হতে পারে (যদিও কিছু দুষ্টু প্রান্তের ক্ষেত্রে সত্ত্বেও )। বিকল্পগুলির উপর গভীর ডুব আলোচনার জন্য এই ব্লগ পোস্টের মন্তব্য বিভাগটি দেখুন: blog.jhades.org/…
খ্রিস্টান

1
ছোট স্পষ্টতা ... যদিও পর্যবেক্ষণযোগ্য উত্সটি কঠোরভাবে ভাগ করা হচ্ছে publishLast().refCount()তা বাতিল করা যাবে না, একবার পর্যবেক্ষণযোগ্য দ্বারা প্রত্যাবর্তনযোগ্য সমস্ত সাবস্ক্রিপশন refCountবাতিল হয়ে গেলে, নিখরচায় উত্সটি পর্যবেক্ষনীয় হয়ে যায়, এটি বাতিল হলে সেখানে বাতিল হবে
খ্রিস্টান

@ খ্রিস্টিয়ান আরে, "বাতিল বা পুনরায় চেষ্টা করা যাবে না" বলে আপনি কী বোঝাতে চেয়েছেন তা কি ব্যাখ্যা করতে পারেন? ধন্যবাদ।
undefined

37

আপডেট: বেন লেশ 5.2.0 এর পরের সামান্য প্রকাশের কথা বলেছে, আপনি কেবল শেয়ারের রিপ্লে () কে সত্যিকারের ক্যাশে কল করতে সক্ষম হবেন।

পূর্বে .....

প্রথমত, ভাগ () বা প্রকাশের জন্য রিপ্লে (1) .refCount () ব্যবহার করবেন না, এগুলি একই এবং সমস্যাটি হ'ল এটি যদি কেবল পর্যবেক্ষণযোগ্য সক্রিয় থাকাকালীন সংযোগগুলি তৈরি করা হয় তবে এটি ভাগ হয় যদি আপনি এটি সম্পন্ন করার পরে সংযোগ করেন , এটি আবার নতুন পর্যবেক্ষণযোগ্য তৈরি করে, অনুবাদ, সত্যিকার অর্থে ক্যাশে করা নয়।

বিরোস্কি উপরেরটি সঠিক সমাধান দিয়েছেন যা রিপ্লেসউবজেক্টটি ব্যবহার করা। রিপ্লেসউবজেক্টটি আমাদের ক্ষেত্রে আপনার দেওয়া মানগুলি (বাফারসাইজ) ক্যাশে করবে 1. এটি রিফকাউন্ট শূন্যে পৌঁছে গেলে এবং নতুন সংযোগ তৈরি করার পরে এটি কোনও নতুন পর্যবেক্ষণযোগ্য তৈরি করবে না, যা ক্যাশিংয়ের জন্য সঠিক আচরণ।

এখানে একটি পুনরায় ব্যবহারযোগ্য ফাংশন

export function cacheable<T>(o: Observable<T>): Observable<T> {
  let replay = new ReplaySubject<T>(1);
  o.subscribe(
    x => replay.next(x),
    x => replay.error(x),
    () => replay.complete()
  );
  return replay.asObservable();
}

এটি কীভাবে ব্যবহার করবেন তা এখানে

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { cacheable } from '../utils/rxjs-functions';

@Injectable()
export class SettingsService {
  _cache: Observable<any>;
  constructor(private _http: Http, ) { }

  refresh = () => {
    if (this._cache) {
      return this._cache;
    }
    return this._cache = cacheable<any>(this._http.get('YOUR URL'));
  }
}

নীচে ক্যাশেযোগ্য ফাংশনটির আরও অগ্রিম সংস্করণ দেওয়া আছে এটির একটি নিজস্ব নিজস্ব সারণী + কাস্টম অনুসন্ধান সারণী সরবরাহ করার ক্ষমতা রাখে has এইভাবে, আপনাকে এটি পরীক্ষা করতে হবে না _ উপরের উদাহরণের মতো ক্যাশে। এছাড়াও লক্ষ্য করুন যে পর্যবেক্ষণযোগ্যটিকে প্রথম যুক্তি হিসাবে পাস করার পরিবর্তে আপনি একটি ফাংশন পাস করেন যা পর্যবেক্ষকদের ফিরিয়ে দেয়, এটি কারণ অ্যাংুলার্স এইচটিটিপি ঠিক তখনই সম্পাদন করে, তাই অলস মৃত্যুদন্ড কার্যকর ফাংশনটি ফিরিয়ে দিয়ে আমরা যদি এটি ইতিমধ্যে উপস্থিত না হয় তবে এটি কল না করার সিদ্ধান্ত নিতে পারি আমাদের ক্যাশে

let cacheableCache: { [key: string]: Observable<any> } = {};
export function cacheable<T>(returnObservable: () => Observable<T>, key?: string, customCache?: { [key: string]: Observable<T> }): Observable<T> {
  if (!!key && (customCache || cacheableCache)[key]) {
    return (customCache || cacheableCache)[key] as Observable<T>;
  }
  let replay = new ReplaySubject<T>(1);
  returnObservable().subscribe(
    x => replay.next(x),
    x => replay.error(x),
    () => replay.complete()
  );
  let observable = replay.asObservable();
  if (!!key) {
    if (!!customCache) {
      customCache[key] = observable;
    } else {
      cacheableCache[key] = observable;
    }
  }
  return observable;
}

ব্যবহার:

getData() => cacheable(this._http.get("YOUR URL"), "this is key for my cache")

সেখানে একটি RxJs অপারেটর হিসাবে এই সমাধান ব্যবহার না করার কোন কারণ আছে কি: const data$ = this._http.get('url').pipe(cacheable()); /*1st subscribe*/ data$.subscribe(); /*2nd subscribe*/ data$.subscribe();? সুতরাং এটি অন্য যে কোনও অপারেটরের মতোই আচরণ করে ..
ফেলিক্স

31

rxjs 5.4.0 এ একটি নতুন শেয়ারের রিপ্লে পদ্ধতি রয়েছে।

লেখক স্পষ্টতই বলেছেন "এজেএক্স ফলাফলগুলি ক্যাশে করার মতো জিনিসগুলি পরিচালনা করার জন্য আদর্শ"

আরএক্সজেএস পিআর # 2443 কীর্তি (শেয়ারের রিপ্লে): এর shareReplayরূপটি যুক্ত করেpublishReplay

শেয়ারের রিপ্লে এমন একটি পর্যবেক্ষণযোগ্য ফেরত দেয় যা একটি রিপ্লেসউবজেক্টের উপর উত্সযুক্ত বহুস্তরযুক্ত। সেই রিপ্লে বিষয়টি উত্স থেকে ত্রুটিতে পুনর্ব্যবহৃত হয়, তবে উত্স সম্পূর্ণ হওয়ার পরে নয়। এটি পুনরায় চেষ্টাযোগ্য হওয়ায় এজেএক্স ফলাফলগুলি ক্যাশে করার মতো জিনিসগুলি পরিচালনা করার জন্য এটি শেয়ারের রিপ্লেকে আদর্শ করে তোলে। এটি পুনরাবৃত্তি আচরণের অংশ থেকে পৃথক যে এটি উত্স পর্যবেক্ষণযোগ্য পুনরাবৃত্তি করবে না, বরং উত্সটি পর্যবেক্ষণযোগ্য মানগুলি পুনরাবৃত্তি করবে।


এটি কি এর সাথে সম্পর্কিত? এই ডক্স যদিও 2014 এর from github.com/Reactive- এক্সটেনশনস
অ্যারন হফম্যান

4
আমি পর্যবেক্ষণযোগ্য হিসাবে .rerePlay (1, 10000) যুক্ত করার চেষ্টা করেছি কিন্তু আমি কোনও ক্যাচিং বা আচরণের পরিবর্তন লক্ষ্য করিনি। কোন কাজের উদাহরণ উপলব্ধ আছে?
আইডাস-ম্যাথিউ

চেঞ্জলগ github.com/ReactiveX/rxjs/blob/… এর দিকে তাকালে এটি আগে উপস্থিত হয়েছিল, v5- এ সরানো হয়েছিল, 5.4-এ ফিরে যুক্ত হয়েছিল - যে rx-book লিঙ্কটি v4-র উল্লেখ করে তবে এটি বর্তমান LTS v5.5.6 এ বিদ্যমান এবং এটি v6 এ আমি কল্পনা করেছি যে আরএক্স-বইয়ের লিঙ্কটি পুরানো।
জেসন আবেদ্রে

25

এই নিবন্ধ অনুযায়ী

দেখা যাচ্ছে যে আমরা সহজেই পাবলিশরেপ্লে (1) এবং রেফকাউন্ট যুক্ত করে পর্যবেক্ষণযোগ্যতে ক্যাচিং যুক্ত করতে পারি।

সুতরাং ভিতরে যদি বিবৃতি শুধু সংযোজন

.publishReplay(1)
.refCount();

প্রতি .map(...)


11

rxjs সংস্করণ 5.4.0 (2017-05-09) জন্য সমর্থন যোগ করা shareReplay

শেয়ারের রিপ্লে কেন ব্যবহার করবেন?

আপনি যখন সাইড-এফেক্টস বা ট্যাক্সিং কম্পিউটেশনগুলি ব্যবহার করেন যা আপনি একাধিক গ্রাহকের মধ্যে মৃত্যুদন্ড কার্যকর করতে চান না তখন আপনি সাধারণত শেয়াররেপ্লে ব্যবহার করতে চান। এটি এমন পরিস্থিতিতেও মূল্যবান হতে পারে যেখানে আপনি জানেন যে আপনার প্রবাহে দেরীতে গ্রাহকরা থাকতে পারে যার পূর্বে নির্গত মানগুলিতে অ্যাক্সেস প্রয়োজন। সাবস্ক্রিপশনে মানগুলি পুনরায় প্লে করার এই ক্ষমতাটি যা ভাগ করে ভাগ করে নেয় তা রিপ্লেতে আলাদা করে।

আপনি এটি ব্যবহার করতে সহজেই একটি কৌণিক পরিষেবা পরিবর্তন করতে পারেন এবং ক্যাশেড ফলাফলের সাথে পর্যবেক্ষণযোগ্য ফিরিয়ে দিতে পারেন যা কেবলমাত্র একবারে এইচটিপি কলকে একবারে করে তুলবে (1 ম কলটি সাফল্যজনক মনে করে)।

কৌণিক পরিষেবা উদাহরণ

এখানে একটি খুব সাধারণ গ্রাহক পরিষেবা যা ব্যবহার করে shareReplay

customer.service.ts

import { shareReplay } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class CustomerService {

    private readonly _getCustomers: Observable<ICustomer[]>;

    constructor(private readonly http: HttpClient) {
        this._getCustomers = this.http.get<ICustomer[]>('/api/customers/').pipe(shareReplay());
    }

    getCustomers() : Observable<ICustomer[]> {
        return this._getCustomers;
    }
}

export interface ICustomer {
  /* ICustomer interface fields defined here */
}

মনে রাখবেন যে কনস্ট্রাক্টরের ক্ষেত্রে অ্যাসাইনমেন্টটি পদ্ধতিতে স্থানান্তরিত হতে পারে getCustomersতবে পর্যবেক্ষকরা যেমন HttpClient"শীতল" হলেন তেমনি কনস্ট্রাক্টরে এটি করা গ্রহণযোগ্য হবে কারণ এইচটিপি কলটি কেবল প্রথম কলটিতেই করা হবে subscribe

এছাড়াও এখানে অনুমান করা হয় যে প্রাথমিক প্রত্যাবর্তিত ডেটা আবেদনের উদাহরণ হিসাবে জীবদ্দশায় বাসি হয় না।


আমি সত্যিই এই প্যাটার্নটি পছন্দ করি এবং এপিআই পরিষেবাদির একটি শেয়ার্ড লাইব্রেরির মধ্যে আমি বেশ কয়েকটি অ্যাপ্লিকেশন জুড়ে ব্যবহার করি এটি প্রয়োগ করতে চাই। একটি উদাহরণ একটি ইউজার সার্ভিস, এবং কয়েকটি জায়গা ব্যতীত অন্য কোথাও অ্যাপের জীবদ্দশায় ক্যাশেটিকে অবৈধ করার দরকার নেই, তবে সেই ক্ষেত্রে, পূর্ববর্তী সাবস্ক্রিপশনগুলি অনাথ হওয়ার কারণে আমি কীভাবে এটি অবৈধ করব?
স্যারটোফামহ্যাট


10

আমি প্রশ্নটি তারাটি দিয়েছি, তবে আমি চেষ্টা করব এবং এগুলি দেখতে পারি।

//this will be the shared observable that 
//anyone can subscribe to, get the value, 
//but not cause an api request
let customer$ = new Rx.ReplaySubject(1);

getCustomer().subscribe(customer$);

//here's the first subscriber
customer$.subscribe(val => console.log('subscriber 1: ' + val));

//here's the second subscriber
setTimeout(() => {
  customer$.subscribe(val => console.log('subscriber 2: ' + val));  
}, 1000);

function getCustomer() {
  return new Rx.Observable(observer => {
    console.log('api request');
    setTimeout(() => {
      console.log('api response');
      observer.next('customer object');
      observer.complete();
    }, 500);
  });
}

এখানে প্রমাণ :)

একটি মাত্র দখল আছে: getCustomer().subscribe(customer$)

আমরা এর এপিআই প্রতিক্রিয়াটির সাবস্ক্রাইব করছি না getCustomer(), আমরা একটি রিপ্লেসউজকে সাবস্ক্রাইব করছি যা পর্যবেক্ষণযোগ্য যা পৃথক পর্যবেক্ষণযোগ্যতেও সাবস্ক্রাইব করতে সক্ষম (এবং এটি গুরুত্বপূর্ণ) এটি শেষ নির্গত মান ধরে রাখতে এবং এটির যে কোনওটিতে এটি পুনরায় প্রকাশ করতে সক্ষম হয় (রিপ্লেসউজেক্টের) ) গ্রাহকগণ।


1
আমি এই পদ্ধতির পছন্দ করি কারণ এটি rxjs এর ভাল ব্যবহার করে এবং কাস্টম যুক্তি যুক্ত করার দরকার নেই, ধন্যবাদ
থিবস

7

আমি এইচটিএসটি ফলাফলটি সেশনস্টোরেজে সংরক্ষণ করার এবং সেশনের জন্য এটি ব্যবহার করার একটি উপায় খুঁজে পেয়েছি, যাতে এটি আর কখনও সার্ভারকে কল না করে।

আমি ব্যবহার সীমা এড়াতে গিথুব এপিআই কল করতে ব্যবহার করেছি।

@Injectable()
export class HttpCache {
  constructor(private http: Http) {}

  get(url: string): Observable<any> {
    let cached: any;
    if (cached === sessionStorage.getItem(url)) {
      return Observable.of(JSON.parse(cached));
    } else {
      return this.http.get(url)
        .map(resp => {
          sessionStorage.setItem(url, resp.text());
          return resp.json();
        });
    }
  }
}

এফওয়াইআই, সেশন স্টোরেজ সীমা 5M (বা 4.75M)। সুতরাং, এটি ডেটার বড় সেট জন্য এই জাতীয় ব্যবহার করা উচিত নয়।

------ সম্পাদনা -------------
আপনি যদি F5- এর সাথে রিফ্রেশ ডেটা রাখতে চান, যা সেশনস্টোরজের পরিবর্তে স্মৃতিযুক্ত ডেটা ব্যবহার করে;

@Injectable()
export class HttpCache {
  cached: any = {};  // this will store data
  constructor(private http: Http) {}

  get(url: string): Observable<any> {
    if (this.cached[url]) {
      return Observable.of(this.cached[url]));
    } else {
      return this.http.get(url)
        .map(resp => {
          this.cached[url] = resp.text();
          return resp.json();
        });
    }
  }
}

আপনি যদি সেশন স্টোরেজে সঞ্চয় করে রাখেন তবে অ্যাপটি ছাড়লে আপনি কীভাবে নিশ্চিত করবেন যে সেশন স্টোরেজটি ধ্বংস হয়ে গেছে?
gags

তবে এটি ব্যবহারকারীর জন্য অপ্রত্যাশিত আচরণের পরিচয় দেয়। যখন ব্যবহারকারী ব্রাউজারের এফ 5 বা রিফ্রেশ বোতামটি হিট করে, তখন সে সার্ভার থেকে নতুন ডেটা আশা করে। কিন্তু আসলে তিনি লোকালস্টোরেজ থেকে পুরানো ডেটা পেয়ে যাচ্ছেন। বাগ রিপোর্ট, সমর্থন টিকিট, ইত্যাদি ইনকামিং ... নাম যেমনটি sessionStorageবলেছে, আমি এটি কেবলমাত্র ডেটা জন্য ব্যবহার করব যা পুরো সেশনের জন্য সামঞ্জস্যপূর্ণ বলে আশা করা হচ্ছে
মার্টিন স্নাইডার

@ এমএ-ম্যাডদিন যেমনটি আমি বলেছি "ব্যবহারের সীমা এড়ানোর জন্য আমি এটি ব্যবহার করেছি"। আপনি যদি F5- এর মাধ্যমে ডেটা রিফ্রেশ করতে চান তবে আপনার সেশন স্টোরেজের পরিবর্তে মেমরিটি ব্যবহার করতে হবে। উত্তরটি এই পদ্ধতির সাথে সম্পাদনা করা হয়েছে।
অ্যালেনহউকিম

হ্যাঁ, এটি ব্যবহারের ক্ষেত্রে হতে পারে। আমি কেবল ট্রিগার পেয়েছি যেহেতু প্রত্যেকে ক্যাশে সম্পর্কে কথা বলছে এবং ওপি getCustomerতার উদাহরণে আছে। ;) তাই কেবল এমন কিছু পিপিএলকে সতর্ক করতে চেয়েছিলেন যা ঝুঁকিগুলি না দেখায় :)
মার্টিন শ্নাইডার

5

আপনি যে বাস্তবায়নটি বেছে নিয়েছেন তা যদি আপনি এইচটিটিপি অনুরোধ বাতিল করতে চান বা সাবস্ক্রাইব করতে চান তবে তার উপর নির্ভর করবে to

যাই হোক না কেন, টাইপস্ক্রিপ্ট সজ্জাকারক আচরণের মানদণ্ডের একটি দুর্দান্ত উপায়। এটিই আমি লিখেছিলাম:

  @CacheObservableArgsKey
  getMyThing(id: string): Observable<any> {
    return this.http.get('things/'+id);
  }

সাজসজ্জার সংজ্ঞা:

/**
 * Decorator that replays and connects to the Observable returned from the function.
 * Caches the result using all arguments to form a key.
 * @param target
 * @param name
 * @param descriptor
 * @returns {PropertyDescriptor}
 */
export function CacheObservableArgsKey(target: Object, name: string, descriptor: PropertyDescriptor) {
  const originalFunc = descriptor.value;
  const cacheMap = new Map<string, any>();
  descriptor.value = function(this: any, ...args: any[]): any {
    const key = args.join('::');

    let returnValue = cacheMap.get(key);
    if (returnValue !== undefined) {
      console.log(`${name} cache-hit ${key}`, returnValue);
      return returnValue;
    }

    returnValue = originalFunc.apply(this, args);
    console.log(`${name} cache-miss ${key} new`, returnValue);
    if (returnValue instanceof Observable) {
      returnValue = returnValue.publishReplay(1);
      returnValue.connect();
    }
    else {
      console.warn('CacheHttpArgsKey: value not an Observable cannot publishReplay and connect', returnValue);
    }
    cacheMap.set(key, returnValue);
    return returnValue;
  };

  return descriptor;
}

হাই @ অ্যারো - উপরের উদাহরণটি সংকলন করে না। Property 'connect' does not exist on type '{}'.লাইন থেকে returnValue.connect();। তুমি কি বিস্তারিত বলতে পারো?
খোঁচা

4

আরএক্সজেএস পর্যবেক্ষক / পর্যবেক্ষণযোগ্য + ক্যাচিং + সাবস্ক্রিপশন ব্যবহার করে ক্যাশেযোগ্য এইচটিটিপি রেসপন্স ডেটা

নীচে কোড দেখুন

* অস্বীকৃতি: আমি আরএক্সজেএসে নতুন, তাই মনে রাখবেন যে আমি পর্যবেক্ষণযোগ্য / পর্যবেক্ষক পদ্ধতির অপব্যবহার করছি। আমার সমাধানটি বিশুদ্ধরূপে আমার পাওয়া অন্যান্য সমাধানগুলির সংমিশ্রণ এবং এটি একটি সাধারণ ভাল-ডকুমেন্টেড সমাধান খুঁজে পেতে ব্যর্থ হওয়ার পরিণতি। এইভাবে আমি আমার সম্পূর্ণ কোড সমাধান সরবরাহ করছি (যেমনটি আমি খুঁজে পেতে চাই) আশা করি যে এটি অন্যকে সহায়তা করে।

* দ্রষ্টব্য, এই পদ্ধতিটি গুগলফায়ারবেসঅবার্সেবলের উপর ভিত্তি করে। দুর্ভাগ্যক্রমে তারা হুডের নীচে কী করেছে তার প্রতিলিপি দেওয়ার জন্য আমার যথাযথ অভিজ্ঞতা / সময়ের অভাব রয়েছে। তবে নিম্নলিখিত কিছু ক্যাশে-সক্ষম ডেটাতে অ্যাসিনক্রোনাস অ্যাক্সেস সরবরাহের একটি সরল পদ্ধতি।

পরিস্থিতি : একটি 'পণ্য-তালিকা' উপাদানকে পণ্যের তালিকা প্রদর্শন করার দায়িত্ব দেওয়া হয়। সাইটটি এমন একক পৃষ্ঠার ওয়েব অ্যাপ্লিকেশন যা কিছু মেনু বোতাম রয়েছে যা পৃষ্ঠায় প্রদর্শিত পণ্যগুলিকে 'ফিল্টার' করবে।

সমাধান : উপাদানটি কোনও পরিষেবা পদ্ধতিতে "সাবস্ক্রাইব করে"। পরিষেবা পদ্ধতিটি পণ্য সামগ্রীর একটি অ্যারে প্রদান করে, যা উপাদান সাবস্ক্রিপশন কলব্যাকের মাধ্যমে অ্যাক্সেস করে। পরিষেবা পদ্ধতিটি নতুনভাবে তৈরি হওয়া পর্যবেক্ষকগুলিতে তার ক্রিয়াকলাপটি মোড় করে এবং পর্যবেক্ষককে ফিরিয়ে দেয়। এই পর্যবেক্ষকের অভ্যন্তরে এটি ক্যাশেড ডেটা অনুসন্ধান করে এবং এটি গ্রাহককে (উপাদানটি) ফেরত দেয় এবং ফিরে আসে। অন্যথায় এটি ডেটা পুনরুদ্ধার করার জন্য একটি http কল জারি করে, প্রতিক্রিয়াটির জন্য সাবস্ক্রাইব করে, যেখানে আপনি সেই ডেটা প্রক্রিয়া করতে পারেন (যেমন আপনার নিজের মডেলটিতে ডেটা ম্যাপ করুন) এবং তারপরে ডেটাটি গ্রাহকের কাছে ফেরত দিন।

কোড

পণ্য-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 (মডেল)

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...
    );
  }
}

Chrome এ পৃষ্ঠাটি লোড করার সময় আমি যে আউটপুটটি দেখি তা এখানে একটি নমুনা Here নোট করুন যে প্রাথমিক লোডে, পণ্যগুলি HTTP থেকে আনা হয় (আমার নোড রেস্ট পরিষেবাতে কল করুন, যা স্থানীয়ভাবে 3000 বন্দরে চলছে)। আমি যখন তখন পণ্যগুলির একটি 'ফিল্টারড' দর্শন নেভিগেট করতে ক্লিক করি তখন পণ্যগুলি ক্যাশে পাওয়া যায়।

আমার ক্রোম লগ (কনসোল):

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

... [পণ্যগুলি ফিল্টার করার জন্য একটি মেনু বোতাম ক্লিক করেছেন] ...

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

উপসংহার: ক্যাশেবল HTTP প্রতিক্রিয়া ডেটা বাস্তবায়নের জন্য এটি আমি এখন পর্যন্ত (এতদূর) সবচেয়ে সহজ উপায়। আমার কৌণিক অ্যাপ্লিকেশনে, প্রতিবার আমি পণ্যগুলির ভিন্ন দৃশ্যে নেভিগেট করি, পণ্য-তালিকা উপাদান পুনরায় লোড করে। প্রোডাক্ট সার্ভিসকে একটি ভাগ করা উদাহরণ বলে মনে হচ্ছে, তাই পণ্যসেবায় 'পণ্যগুলি: পণ্য []' এর স্থানীয় ক্যাশে নেভিগেশনের সময় ধরে রাখা হয় এবং পরবর্তীকালে "গেটপড্রুক্টস ()" এ কল করা ক্যাশেড মানটি দেয়। একটি চূড়ান্ত নোট, আমি যখন 'স্মৃতি স্মৃতি ফাঁস' রোধ করার জন্য পর্যবেক্ষণযোগ্য / সাবস্ক্রিপশনগুলি বন্ধ করার দরকার হয় সে সম্পর্কে মন্তব্যগুলি পড়েছি। আমি এটিকে এখানে অন্তর্ভুক্ত করি নি তবে এটি মনে রাখা দরকার something


1
দ্রষ্টব্য - এর পর থেকে আমি আরও শক্তিশালী সমাধান পেয়েছি, এতে আরএক্সজেএস বিহেভিয়ারসুবেক্টস জড়িত রয়েছে যা কোডটি সরল করে এবং নাটকীয়ভাবে 'ওভারহেড' কেটে দেয়। Product.service.ts এ, 1. 'rxjs' থেকে} আচরণের সাবজেক্ট import আমদানি করুন; ২. 'পণ্যগুলি: পণ্য []' কে 'পণ্যতে পরিবর্তন করুন': আচরণবিধি <পণ্য [] [= নতুন আচরণবিধি <পণ্য []> ([]]; ' ৩. এখন আপনি কিছু না ফিরিয়েই কেবল এইচটিপিকে কল করতে পারবেন। http_getProducts () {this.http.get (...)। map (res => res.json ())। সাবস্ক্রাইব করুন (পণ্য => এটি.প্রডাক্ট ne। প্রবন্ধ (পণ্য))};
উদ্দেশ্য

1
স্থানীয় পরিবর্তনশীল 'পণ্য $' হ'ল একটি আচরণশক্তি, যা ইএমআইটি এবং স্টোর উভয় সর্বশেষ পণ্যগুলি (পণ্য থেকে from .Nxt (..) অংশে কল 3) করবে। এখন আপনার উপাদানগুলিতে, পরিষেবাটি স্বাভাবিক হিসাবে ইনজেক্ট করুন। আপনি পণ্যের সর্বাধিক বরাদ্দকৃত মূল্য পাবেন product productService.pr Prodct $। মূল্য ব্যবহার করে। বা পণ্যের সাবস্ক্রাইব করুন you আপনি যখনই কোনও ক্রিয়া সম্পাদন করতে চান তবে পণ্য $ একটি নতুন মান (অর্থাত্, পণ্যটি $। নেক্সট (...) ফাংশনটি কল করা হয় অংশ 3) $
উদ্দেশ্য

1
উদাহরণস্বরূপ, প্রোডাক্টস.কমেন্ট.টায় ... এই.প্রডাক্টসোর্সেস.প্রডাক্ট $ .টেকইউন্টিল (this.ngUnsubscribe)। সাবস্ক্রাইব ((পণ্য) => {this.category); ফিল্টারডপ্রডাক্টস = এটি.প্রডাক্টসওয়ার্স.জেটপ্রডাক্টবাইবাই ক্যাটাগরি (এটির বিভাগ); this.products = ফিল্টারপ্রডাক্টস; });
উদ্দেশ্য

1
পর্যবেক্ষণযোগ্যদের থেকে সাবস্ক্রাইব সম্পর্কে একটি গুরুত্বপূর্ণ নোট: ".টেকইউন্টিল (this.ngUnsubscribe)"। এই স্ট্যাকের ওভারফ্লো প্রশ্ন / উত্তরটি দেখুন, যা ইভেন্টগুলি থেকে সাবস্ক্রাইব করার 'ডি-ফ্যাক্টো' প্রস্তাবিত উপায় দেখায়: স্ট্যাকওভারফ্লো
উদ্দেশ্য 4

1
বিকল্পটি প্রথম ফার্স্ট () বা .টেক (1) এর পক্ষে হয় যদি পর্যবেক্ষণযোগ্য কেবল একবার ডেটা প্রাপ্ত করার জন্য বোঝায়। পর্যবেক্ষণযোগ্য অন্যান্য সমস্ত 'অসীম স্রোত' 'এনজিওনডেস্ট্রয় ()' এ সাবস্ক্রাইব করা উচিত, এবং যদি আপনি তা না করেন তবে আপনি নকল 'পর্যবেক্ষণযোগ্য' কলব্যাকগুলি দিয়ে শেষ করতে পারেন। stackoverflow.com/questions/28007777/…
উদ্দেশ্য

3

আমি ধরে নিয়েছি যে @ এনজিএক্স-ক্যাশে / কোরটি HTTP কলগুলির জন্য ক্যাচিং বৈশিষ্ট্য বজায় রাখতে কার্যকর হতে পারে, বিশেষত যদি HTTP কলটি ব্রাউজার এবং সার্ভার প্ল্যাটফর্ম উভয় ক্ষেত্রেই করা হয় ।

ধরা যাক আমাদের নিম্নলিখিত পদ্ধতি রয়েছে:

getCustomer() {
  return this.http.get('/someUrl').map(res => res.json());
}

আপনি ব্যবহার করতে পারেন Cachedএর প্রসাধক @ ngx-ক্যাশে / কোর পদ্ধতি এ HTTP- র কল করার থেকে প্রত্যাগত মান সংরক্ষণ করতে cache storage( কনফিগারযোগ্য হতে পারে, এ বাস্তবায়ন চেক করুন NG-বীজ / সার্বজনীন প্রথম ফাঁসি ডানে -)। পরের বারটি পদ্ধতিটি আহ্বান করা হয়েছে ( ব্রাউজার বা সার্ভার প্ল্যাটফর্মের কোনও বিষয় নয় ), মানটি থেকে প্রাপ্ত করা হয় ।storagecache storage

import { Cached } from '@ngx-cache/core';

...

@Cached('get-customer') // the cache key/identifier
getCustomer() {
  return this.http.get('/someUrl').map(res => res.json());
}

এছাড়া ব্যবহার ক্যাশে পদ্ধতি (সম্ভাবনা has, get, set) ব্যবহার করে ক্যাশে এপিআই

anyclass.ts

...
import { CacheService } from '@ngx-cache/core';

@Injectable()
export class AnyClass {
  constructor(private readonly cache: CacheService) {
    // note that CacheService is injected into a private property of AnyClass
  }

  // will retrieve 'some string value'
  getSomeStringValue(): string {
    if (this.cache.has('some-string'))
      return this.cache.get('some-string');

    this.cache.set('some-string', 'some string value');
    return 'some string value';
  }
}

ক্লায়েন্ট-সাইড এবং সার্ভার-সাইড ক্যাশে উভয়ের জন্য প্যাকেজগুলির তালিকা এখানে রয়েছে:


1

rxjs 5.3.0

আমি খুশি হইনি .map(myFunction).publishReplay(1).refCount()

একাধিক গ্রাহক, .map()executes myFunctionকিছু ক্ষেত্রে (আমি এটা শুধুমাত্র একবার চালানো আশা) দুবার। একটি ঠিক আছে বলে মনে হচ্ছেpublishReplay(1).refCount().take(1)

আর একটি জিনিস যা আপনি করতে পারেন তা হ'ল refCount()অবিলম্বে পর্যবেক্ষণযোগ্যকে গরম করে তুলুন:

let obs = this.http.get('my/data.json').publishReplay(1);
obs.connect();
return obs;

এটি গ্রাহক নির্বিশেষে এইচটিটিপি অনুরোধ শুরু করবে। আমি নিশ্চিত নই যে এইচটিটিপি জিইটি শেষ হওয়ার আগে সদস্যতা বাতিল করা বাতিল করে দেবে কিনা।


1

আমরা কী করতে চাই তা নিশ্চিত করা যায় যে এটি একাধিক নেটওয়ার্ক অনুরোধের কারণ নয়।

asyncনেটওয়ার্কগুলির অনুরোধগুলি করার জন্য কলগুলির জন্য পদ্ধতি ব্যবহার করা আমার ব্যক্তিগত প্রিয় । পদ্ধতিগুলি নিজেরাই কোনও মান ফেরায় না, পরিবর্তে তারা একটি আপডেট করেBehaviorSubject একই পরিষেবাতে , যা উপাদানগুলি সাবস্ক্রাইব করবে।

এখন কেন একটি BehaviorSubjectপরিবর্তে একটি ব্যবহার Observable? কারণ,

  • সাবস্ক্রিপশনের পরে আচরণসাধকটি সর্বশেষ মানটি প্রদান করে যখন একটি নিয়মিত পর্যবেক্ষণযোগ্য কেবল তখনই ট্রিগার হয় যখন এটি প্রাপ্ত হয় onnext
  • আপনি যদি অ-পর্যবেক্ষণযোগ্য কোডে (সাবস্ক্রিপশন ছাড়াই) আচরণবিধিটির শেষ মানটি পুনরুদ্ধার করতে চান তবে আপনি এই getValue()পদ্ধতিটি ব্যবহার করতে পারেন ।

উদাহরণ:

customer.service.ts

public customers$: BehaviorSubject<Customer[]> = new BehaviorSubject([]);

public async getCustomers(): Promise<void> {
    let customers = await this.httpClient.post<LogEntry[]>(this.endPoint, criteria).toPromise();
    if (customers) 
        this.customers$.next(customers);
}

তারপরে, যেখানেই প্রয়োজন, আমরা কেবল সাবস্ক্রাইব করতে পারি customers$

public ngOnInit(): void {
    this.customerService.customers$
    .subscribe((customers: Customer[]) => this.customerList = customers);
}

অথবা আপনি এটি সরাসরি কোনও টেম্পলেটে ব্যবহার করতে চান

<li *ngFor="let customer of customerService.customers$ | async"> ... </li>

সুতরাং এখন, আপনি অন্য কোনও কল না করা পর্যন্ত getCustomers, customers$আচরণটি সাবজেক্টে ডেটা বজায় থাকে ।

সুতরাং আপনি যদি এই তথ্যটি রিফ্রেশ করতে চান? শুধু একটি কল করুনgetCustomers()

public async refresh(): Promise<void> {
    try {
      await this.customerService.getCustomers();
    } 
    catch (e) {
      // request failed, handle exception
      console.error(e);
    }
}

এই পদ্ধতি ব্যবহার করে, আমরা যেমন দ্বারা পরিচালিত হচ্ছে স্পষ্টভাবে পরবর্তী নেটওয়ার্কের কল মধ্যে ডেটা ধরে রাখা হবে না BehaviorSubject

পিএস: সাধারণত যখন কোনও উপাদান ধ্বংস হয়ে যায় তখন সাবস্ক্রিপশনগুলি থেকে মুক্তি পাওয়ার জন্য এটি একটি ভাল অনুশীলন, এজন্য আপনি এই উত্তরে প্রস্তাবিত পদ্ধতিটি ব্যবহার করতে পারেন ।


1

দুর্দান্ত উত্তর।

অথবা আপনি এটি করতে পারেন:

এটি rxjs এর সর্বশেষ সংস্করণ থেকে। আমি ব্যবহার করছি 5.5.7 সংস্করণ RxJS

import {share} from "rxjs/operators";

this.http.get('/someUrl').pipe(share());

0

মানচিত্রের পরে এবং যে কোনও সাবস্ক্রাইব করার আগে কেবল ভাগ কল করুন ()

আমার ক্ষেত্রে, আমার কাছে একটি জেনেরিক সার্ভিস রয়েছে (রেস্টক্লিয়েন্টসর্স.স.) যারা বিশ্রাম কল করছে, তথ্য আহরণ করছে, ত্রুটিগুলি যাচাই করে এবং একটি কংক্রিট বাস্তবায়ন পরিষেবায় পর্যবেক্ষণযোগ্য ফিরে আসবে (f.ex .: চুক্তিপরিষ্কার পরিষেবা) ডি কন্ট্রাক্ট কম্পোনেন্ট.টিতে পর্যবেক্ষণযোগ্য ফেরত দেয় এবং ভিউ আপডেট করার জন্য এটি সাবস্ক্রাইব করে।

RestClientService.ts:

export abstract class RestClientService<T extends BaseModel> {

      public GetAll = (path: string, property: string): Observable<T[]> => {
        let fullPath = this.actionUrl + path;
        let observable = this._http.get(fullPath).map(res => this.extractData(res, property));
        observable = observable.share();  //allows multiple subscribers without making again the http request
        observable.subscribe(
          (res) => {},
          error => this.handleError2(error, "GetAll", fullPath),
          () => {}
        );
        return observable;
      }

  private extractData(res: Response, property: string) {
    ...
  }
  private handleError2(error: any, method: string, path: string) {
    ...
  }

}

ContractService.ts:

export class ContractService extends RestClientService<Contract> {
  private GET_ALL_ITEMS_REST_URI_PATH = "search";
  private GET_ALL_ITEMS_PROPERTY_PATH = "contract";
  public getAllItems(): Observable<Contract[]> {
    return this.GetAll(this.GET_ALL_ITEMS_REST_URI_PATH, this.GET_ALL_ITEMS_PROPERTY_PATH);
  }

}

ContractComponent.ts:

export class ContractComponent implements OnInit {

  getAllItems() {
    this.rcService.getAllItems().subscribe((data) => {
      this.items = data;
   });
  }

}

0

আমি একটি ক্যাশে ক্লাস লিখেছি,

/**
 * Caches results returned from given fetcher callback for given key,
 * up to maxItems results, deletes the oldest results when full (FIFO).
 */
export class StaticCache
{
    static cachedData: Map<string, any> = new Map<string, any>();
    static maxItems: number = 400;

    static get(key: string){
        return this.cachedData.get(key);
    }

    static getOrFetch(key: string, fetcher: (string) => any): any {
        let value = this.cachedData.get(key);

        if (value != null){
            console.log("Cache HIT! (fetcher)");
            return value;
        }

        console.log("Cache MISS... (fetcher)");
        value = fetcher(key);
        this.add(key, value);
        return value;
    }

    static add(key, value){
        this.cachedData.set(key, value);
        this.deleteOverflowing();
    }

    static deleteOverflowing(): void {
        if (this.cachedData.size > this.maxItems) {
            this.deleteOldest(this.cachedData.size - this.maxItems);
        }
    }

    /// A Map object iterates its elements in insertion order — a for...of loop returns an array of [key, value] for each iteration.
    /// However that seems not to work. Trying with forEach.
    static deleteOldest(howMany: number): void {
        //console.debug("Deleting oldest " + howMany + " of " + this.cachedData.size);
        let iterKeys = this.cachedData.keys();
        let item: IteratorResult<string>;
        while (howMany-- > 0 && (item = iterKeys.next(), !item.done)){
            //console.debug("    Deleting: " + item.value);
            this.cachedData.delete(item.value); // Deleting while iterating should be ok in JS.
        }
    }

    static clear(): void {
        this.cachedData = new Map<string, any>();
    }

}

আমরা কীভাবে এটি ব্যবহার করি তার কারণেই এটি সমস্ত স্থিতিশীল, তবে এটিকে একটি সাধারণ বর্গ এবং একটি পরিষেবা হিসাবে নির্দ্বিধায় অনুভব করে। আমি নিশ্চিত নই যে কৌণিক পুরো সময়ের জন্য একক উদাহরণ রাখলেও (Angular2 তে নতুন)।

এবং এটি আমি এটি ব্যবহার করি:

            let httpService: Http = this.http;
            function fetcher(url: string): Observable<any> {
                console.log("    Fetching URL: " + url);
                return httpService.get(url).map((response: Response) => {
                    if (!response) return null;
                    if (typeof response.json() !== "array")
                        throw new Error("Graph REST should return an array of vertices.");
                    let items: any[] = graphService.fromJSONarray(response.json(), httpService);
                    return array ? items : items[0];
                });
            }

            // If data is a link, return a result of a service call.
            if (this.data[verticesLabel][name]["link"] || this.data[verticesLabel][name]["_type"] == "link")
            {
                // Make an HTTP call.
                let url = this.data[verticesLabel][name]["link"];
                let cachedObservable: Observable<any> = StaticCache.getOrFetch(url, fetcher);
                if (!cachedObservable)
                    throw new Error("Failed loading link: " + url);
                return cachedObservable;
            }

আমি ধরে নিচ্ছি আরও চতুর উপায় থাকতে পারে, যা কিছু Observableকৌশল ব্যবহার করবে তবে এটি আমার উদ্দেশ্যগুলির জন্য ঠিক ছিল।


0

কেবল এই ক্যাশে স্তরটি ব্যবহার করুন, এটি আপনার প্রয়োজনীয় সমস্ত কিছু করে এবং এমনকি এজাক্স অনুরোধগুলির জন্য ক্যাশে পরিচালনা করে।

http://www.ravinderpayal.com/blogs/12Jan2017-Ajax-Cache-Mangement-Angular2-Service.html

এটি ব্যবহার করা অনেক সহজ

@Component({
    selector: 'home',
    templateUrl: './html/home.component.html',
    styleUrls: ['./css/home.component.css'],
})
export class HomeComponent {
    constructor(AjaxService:AjaxService){
        AjaxService.postCache("/api/home/articles").subscribe(values=>{console.log(values);this.articles=values;});
    }

    articles={1:[{data:[{title:"first",sort_text:"description"},{title:"second",sort_text:"description"}],type:"Open Source Works"}]};
}

স্তরটি (ইনজেকশন-সক্ষম কৌণিক পরিষেবা হিসাবে)

import { Injectable }     from '@angular/core';
import { Http, Response} from '@angular/http';
import { Observable }     from 'rxjs/Observable';
import './../rxjs/operator'
@Injectable()
export class AjaxService {
    public data:Object={};
    /*
    private dataObservable:Observable<boolean>;
     */
    private dataObserver:Array<any>=[];
    private loading:Object={};
    private links:Object={};
    counter:number=-1;
    constructor (private http: Http) {
    }
    private loadPostCache(link:string){
     if(!this.loading[link]){
               this.loading[link]=true;
               this.links[link].forEach(a=>this.dataObserver[a].next(false));
               this.http.get(link)
                   .map(this.setValue)
                   .catch(this.handleError).subscribe(
                   values => {
                       this.data[link] = values;
                       delete this.loading[link];
                       this.links[link].forEach(a=>this.dataObserver[a].next(false));
                   },
                   error => {
                       delete this.loading[link];
                   }
               );
           }
    }

    private setValue(res: Response) {
        return res.json() || { };
    }

    private handleError (error: Response | any) {
        // In a real world app, we might use a remote logging infrastructure
        let errMsg: string;
        if (error instanceof Response) {
            const body = error.json() || '';
            const err = body.error || JSON.stringify(body);
            errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
        } else {
            errMsg = error.message ? error.message : error.toString();
        }
        console.error(errMsg);
        return Observable.throw(errMsg);
    }

    postCache(link:string): Observable<Object>{

         return Observable.create(observer=> {
             if(this.data.hasOwnProperty(link)){
                 observer.next(this.data[link]);
             }
             else{
                 let _observable=Observable.create(_observer=>{
                     this.counter=this.counter+1;
                     this.dataObserver[this.counter]=_observer;
                     this.links.hasOwnProperty(link)?this.links[link].push(this.counter):(this.links[link]=[this.counter]);
                     _observer.next(false);
                 });
                 this.loadPostCache(link);
                 _observable.subscribe(status=>{
                     if(status){
                         observer.next(this.data[link]);
                     }
                     }
                 );
             }
            });
        }
}

0

এটি .publishReplay(1).refCount();বা .publishLast().refCount();যেহেতু কৌণিক এইচটিটিপি অনুরোধের পরে সম্পূর্ণ পর্যবেক্ষণযোগ্য।

এই সাধারণ শ্রেণিটি ফলাফলটিকে ক্যাশে করে যাতে আপনি। মূল্যবান হয়ে অনেকবার সাবস্ক্রাইব করতে পারেন এবং কেবল 1 টি অনুরোধ করেন। আপনি নতুন অনুরোধ করতে এবং ডেটা প্রকাশ করতে .reload () ব্যবহার করতে পারেন।

আপনি এটি ব্যবহার করতে পারেন:

let res = new RestResource(() => this.http.get('inline.bundleo.js'));

res.status.subscribe((loading)=>{
    console.log('STATUS=',loading);
});

res.value.subscribe((value) => {
  console.log('VALUE=', value);
});

এবং উত্স:

export class RestResource {

  static readonly LOADING: string = 'RestResource_Loading';
  static readonly ERROR: string = 'RestResource_Error';
  static readonly IDLE: string = 'RestResource_Idle';

  public value: Observable<any>;
  public status: Observable<string>;
  private loadStatus: Observer<any>;

  private reloader: Observable<any>;
  private reloadTrigger: Observer<any>;

  constructor(requestObservableFn: () => Observable<any>) {
    this.status = Observable.create((o) => {
      this.loadStatus = o;
    });

    this.reloader = Observable.create((o: Observer<any>) => {
      this.reloadTrigger = o;
    });

    this.value = this.reloader.startWith(null).switchMap(() => {
      if (this.loadStatus) {
        this.loadStatus.next(RestResource.LOADING);
      }
      return requestObservableFn()
        .map((res) => {
          if (this.loadStatus) {
            this.loadStatus.next(RestResource.IDLE);
          }
          return res;
        }).catch((err)=>{
          if (this.loadStatus) {
            this.loadStatus.next(RestResource.ERROR);
          }
          return Observable.of(null);
        });
    }).publishReplay(1).refCount();
  }

  reload() {
    this.reloadTrigger.next(null);
  }

}

0

আপনি সাধারণ শ্রেণীর ক্যাশেযোগ্য <> নির্মাণ করতে পারেন যা একাধিক গ্রাহক সহ HTTP সার্ভার থেকে প্রাপ্ত ডেটা পরিচালনায় সহায়তা করে:

declare type GetDataHandler<T> = () => Observable<T>;

export class Cacheable<T> {

    protected data: T;
    protected subjectData: Subject<T>;
    protected observableData: Observable<T>;
    public getHandler: GetDataHandler<T>;

    constructor() {
      this.subjectData = new ReplaySubject(1);
      this.observableData = this.subjectData.asObservable();
    }

    public getData(): Observable<T> {
      if (!this.getHandler) {
        throw new Error("getHandler is not defined");
      }
      if (!this.data) {
        this.getHandler().map((r: T) => {
          this.data = r;
          return r;
        }).subscribe(
          result => this.subjectData.next(result),
          err => this.subjectData.error(err)
        );
      }
      return this.observableData;
    }

    public resetCache(): void {
      this.data = null;
    }

    public refresh(): void {
      this.resetCache();
      this.getData();
    }

}

ব্যবহার

ক্যাশেযোগ্য <> অবজেক্টটি (সম্ভবত পরিষেবাটির অংশ হিসাবে) ঘোষণা করুন:

list: Cacheable<string> = new Cacheable<string>();

এবং হ্যান্ডলার:

this.list.getHandler = () => {
// get data from server
return this.http.get(url)
.map((r: Response) => r.json() as string[]);
}

কোনও উপাদান থেকে কল করুন:

//gets data from server
List.getData().subscribe(…)

আপনার এটিতে বেশ কয়েকটি উপাদান সদস্যতা পেতে পারে।

আরও বিশদ এবং কোড উদাহরণ এখানে: http://devinstance.net/articles/20171021/rxjs- কেসযোগ্য


0

আপনি কেবল এনজিএক্স-ক্যাশেবল ব্যবহার করতে পারেন ! এটি আপনার দৃশ্যের সাথে আরও ভাল মানায়।

এটি ব্যবহার করে সুবিধা

  • এটি একবারে রেস্ট এআইপি কল করে, প্রতিক্রিয়াটিকে ক্যাশে করে এবং নিম্নলিখিত অনুরোধগুলির জন্য একইটি প্রদান করে।
  • অপারেশন তৈরি / আপডেট / মুছে ফেলার পরে প্রয়োজনীয় হিসাবে API কে কল করতে পারেন।

সুতরাং, আপনার পরিষেবা শ্রেণিটি এরকম কিছু হবে -

import { Injectable } from '@angular/core';
import { Cacheable, CacheBuster } from 'ngx-cacheable';

const customerNotifier = new Subject();

@Injectable()
export class customersService {

    // relieves all its caches when any new value is emitted in the stream using notifier
    @Cacheable({
        cacheBusterObserver: customerNotifier,
        async: true
    })
    getCustomer() {
        return this.http.get('/someUrl').map(res => res.json());
    }

    // notifies the observer to refresh the data
    @CacheBuster({
        cacheBusterNotifier: customerNotifier
    })
    addCustomer() {
        // some code
    }

    // notifies the observer to refresh the data
    @CacheBuster({
        cacheBusterNotifier: customerNotifier
    })
    updateCustomer() {
        // some code
    }
}

এখানে 'আরও রেফারেন্সের জন্য লিংক s।


-4

আপনি ইতিমধ্যে কোডটি চালানোর চেষ্টা করেছেন?

যেহেতু আপনি প্রাপ্ত প্রতিশ্রুতি থেকে পর্যবেক্ষণযোগ্য নির্মাণ করছেন getJSON(), তাই কারও সাবস্ক্রাইব করার আগে নেটওয়ার্ক অনুরোধ করা হবে। এবং ফলস্বরূপ প্রতিশ্রুতি সমস্ত গ্রাহকরা ভাগ করে নিচ্ছেন।

var promise = jQuery.getJSON(requestUrl); // network call is executed now
var o = Rx.Observable.fromPromise(promise); // just wraps it in an observable
o.subscribe(...); // does not trigger network call
o.subscribe(...); // does not trigger network call
// ...

আমি এটিকে কৌনিক 2 নির্দিষ্ট করার জন্য প্রশ্নটি সম্পাদনা করেছি
কৌণিক বিশ্ববিদ্যালয়
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.