再利用可能なJavaScript Caching Proxy

問題


今日までのパフォーマンスがWebアプリケーションの品質の主要な指標の1つであることは周知の事実です。 そしてもちろん、Web開発者はアプリケーションを最適化し、サーバー側とクライアント側の両方で許容可能なパフォーマンスを達成するために1時間以上を費やしました。 ハードウェアが日々ますます強力になっているという事実にもかかわらず、回避が困難なボトルネックが常に存在します。 AJAXの出現により、HTTPリクエストはクライアントごとに受信されるデータ量の観点から「小さくなりました」が、その数は増加しました。 通信チャネルは非常に広い可能性がありますが、接続時間とサーバー上で応答を形成するプロセスにはかなりの時間がかかる場合があります。 クライアントでクエリ結果をキャッシュすると、全体的なパフォーマンスが大幅に向上します。 キャッシュはHTTPプロトコルレベルで構成できるという事実にもかかわらず、多くの場合、実際の要件を満たしていません。

挑戦する


クライアントキャッシングシステムは、次の要件を満たしている必要があります。
  1. 複雑なキャッシュ管理ロジックを実装する機能。
  2. さまざまなアプリケーションで再利用する機能。
  3. 既存のアプリケーションに透過的に埋め込む機能。
  4. データのタイプとその取得方法の独立性。
  5. キャッシュされたデータを保存する方法からの独立。

既存のアプリケーション


jQueryを使用してAJAXを介してサーバーからマークアップまたはデータを取得する動作中のアプリケーションがすでにあるとします。

function myApp() { this.doMyAjax = function (settings) { settings.method = 'get'; settings.error = function (jqXHR, textStatus, errorThrown) { //handle error here } $.ajax(settings); } this.myServerDataAccess = function() { doMyAjax({ url: 'myUrl', success: function (data, textStatus, jqXHR) { //handle response here } }); } } 


どこかで、データを呼び出すメソッドを呼び出します。

 var app = new myApp(); app.myServerDataAccess(); 


キャッシングレイヤー


最も簡単なキャッシングレイヤーを実装します。これは、データとキャッシュへのアクセスを制御するプロキシで構成されます。

プロキシされるインターフェイスは、単一のgetDataメソッドで構成されます。 完全に透過的なプロキシは、同じインターフェイスを使用して呼び出しをデータソースに委任するだけです。

 function cacheProxy(source) { var source = source; this.getData = function (request, success, fail) { source.getData(request, success, fail); } } 


キャッシュにアクセスするためのロジックを追加します。これについては後ほど実装します。

 function cacheProxy(source, useLocalStorage) { var source = source; var cache = new localCache(useLocalStorage); this.getData = function (request, success, fail) { var fromCache = cache.get(request.id); if (fromCache !== null) { success(fromCache); } else { source.getData(request, function (result) { cache.set(request.id, result); success(result); }, fail); } } } 


データを取得しようとすると、プロキシはキャッシュ内の存在を確認し、存在するかどうかを確認します。 そうでない場合は、ソースを使用してそれらを受け取り、キャッシュに入れてリクエスターに渡します。

ローカルストレージにデータを配置する機能を備えたキャッシュを実装します

 function localCache(useLocalStorage) { var data = useLocalStorage ? window.localStorage || {} : {}; this.get = function (key) { if (key in data) { return JSON.parse(data[key]); } return null; } this.set = function (key, value) { if (typeof (key) != 'string') { throw 'Key must be of string type.'; } if (value === null || typeof (value) == 'undefined') { throw 'Unexpected value type'; } data[key] = JSON.stringify(value); } } 


データは、キー/シリアル化されたキャッシュデータのペアとして保存されます。

既存のアプリケーションへの統合


ご覧のとおり、既存のアプリケーションと結果のプロキシのデータアクセスインターフェイスは異なります(これが私たちの生活を複雑にする試みだとは思わないでください。これはデモンストレーションのために意図的に行いました)。 統合するには、プロキシ化されたインターフェイスを実装するアダプタを作成して適用するだけで十分です。

 function applyCacheProxyToMyApp(app) { var app = app; app.old_doMyAjax = app.doMyAjax; var proxy = new cacheProxy(this, true); app.doMyAjax = function (settings) { proxy.getData({ id: settings.url }, settings.success, settings.error); } this.getData = function (request, success, fail) { app.old_doMyAjax({ url: request.id, success: success, error: fail }); } } var patch = new applyCacheProxyToMyApp(app); 


ご覧のとおり、既存のアプリケーションの1行のコードは変更していません。 キャッシュは痛みを伴わずにオフにすることも、必要に応じて破棄することもできます。 理解を複雑にしないために、キャッシュクリーニングアルゴリズムを実装しません。 特定のアプリケーションの特定の要件に依存する場合があります。

ボーナス


結果のキャッシングレイヤーは、たとえばリソースを大量に消費する繰り返し操作に簡単に適用できます。

 function complicatedStuff(a, b) { return a * b; } function complicatedStuffAdapter(complicatedStuff) { var proxy = new cacheProxy(this, true); var source = complicatedStuff; this.complicatedStuff = function (a, b) { var result; proxy.getData({id: a.toString() + '_' + b, a: a, b: b}, function(res) { result = res; }); return result; } this.getData = function (request, success, fail) { success(source(request.a, request.b)); } } var p = new complicatedStuffAdapter(complicatedStuff); function test() { alert(p.complicatedStuff(4, 5)); } 


結論として


アプリケーションが実行する操作をプロキシする方法のみを検討しました。 多くのアプリケーションがあります。 ロギングから、複雑なアスペクト指向アルゴリズムの実装まで、すべてはニーズと想像力に依存します。

Source: https://habr.com/ru/post/J131690/


All Articles