Local First Softwareを実装するのに役立つフレームワークです。
Replicacheはサーバーデータの同期を後から非同期的に実行し、サーバーのラウンドトリップを排除し、即時UI変更を可能にします。Replicache Parts
Replicache
Webアプリケーションのような私たちが作ったアプリケーションである。 Replicacheに状態を保存する主体である。
最も信頼できるデータを保存するために存在します。
サーバーはpush(upstream)とpull(downstream)を実装してクライアントのReplicacheと通信する必要があります。push(upstream): Replicache は変更を push endpoint に送る。 🎜>
pull(downstream):定期的または明示的に要求すると、Replicacheはサーバーにプル要求を送信します。サーバーはクライアントがサーバーの状態と同じになるために必要な変更を返します。 >
アプリケーションとサーバーが最新の状態に同期する 以下の図がこの過程をよく示しています。にプッシュされる過程を見せる。
クライアントは通常1つのタブに1つ存在します。
Client Groupは、ローカルデータを共有するクライアントの集まりです。このクライアントグループ内のクライアントは、オフライン状態でも状態を共有します。
Client Groupは、Replicacheのコンストラクタのnameパラメータによって区別されるon-disk persistent cacheを使用します。同じ名前を持つクライアントグループに属するすべてのクライアントは同じキャッシュを共有します。
Client は ordered map of key value pair を persistent cache に持っていますが、これを Client View と呼びます。 Client Viewはアプリケーションのデータであり、サーバーのデータと同期されます。 Client Viewと呼ばれる理由は、異なるクライアントごとにサーバーのデータを異なるClient Viewに持つことができるからです。各クライアントがサーバーの状態を見るのが異なるという意味だ。
Client Viewにアクセスするのは非常に高速です。 Read latency は 1ms 未満で、ほとんどのデバイスで 500MB/s の Throughput を持ちます。
React同じ場所でuseStateに別々にClient Viewをコピーしてメモリに置いて使用しないでください。 Client Viewにmutatorが変更を加えるとsubscriptionが発動され、UIが更新されるようにすればよい。Subscriptions
SubscriptionでUIを設定すれば、常に最新の状態に保つことができる。
Mutations
import {Replicache} from "replicache"; const rep = new Replicache({ name: userID, ... }); console.log(rep.clientID);
Mutatorは以下のように動作させる。 Mutatorが機能するとデータが変更され、それに関連するサブスクリプションがトリガーされ、UIも変更されます。
const todos = useSubscribe(rep, async tx => { return await tx.scan({prefix: 'todo/'}).toArray(); }); return ( <ul> {todos.map(todo => ( <li key={todo.id}>{todo.text}</li> ))} </ul> );
内部的にMutatorはmutationというものを作る。実行履歴と同じですが、Replicacheは以下のようなミューテーションを生成します。
const rep = new Replicache({ ... mutators: { createTodo, markTodoComplete, }, }); async function createTodo(tx: WriteTransaction, todo: Todo) { await tx.set(`/todo/${todo.id}`, todo); } async function markTodoComplete(tx: WriteTransaction, {id, complete}: {id: string, complete: boolean}) { const key = `/todo/${id}`; const todo = await tx.get(key); if (!todo) { return; } todo.complete = complete; await tx.set(key, todo); }
これでReplicacheの核心といえるSyncの詳細な内容だ。 Syncはサーバー上で行われます。
(これから「状態」という表現は、複数のkeyとvalueペアのデータ(key value space)の状態を意味する。)
Replicacheが解決しようとするSyncの問題は、複数のクライアントが同時に同じ状態を変化させる状況であり、以下のような条件を持つ場合に発生します。
Local execution
プッシュ
mutation はサーバに実装された mutator を実行させて canonical 状態を変更する。 Mutationを適用しながら、このクライアントのlast mutation idを更新し、このクライアントが次のプルを行うとき、どのmutationから再適用するかを知ることができる値になる。
ローカルに適用されたpending mutationはspeculative resultを生成し、サーバに適用されたmutationはcanonical resultを生成する。サーバーに適用された mutation は confirmed され、再びローカルで実行されません。もし同じミューテーションが別の結果を返しても、サーバーの canonical result が優先されるので、クライアントの結果は変わります。プル
Pull requestはcookie、clientGroupIdを入れて要求し、new cookie、patch、lastMutationIDChangesを返します。
cookieは、クライアントが持っているサーバーの状態を区別するために使用されます。サーバーとクライアントの状態がどれだけ変化しているかを追跡できる値です。データベースの状態が変わるたびに変更されるグローバル'version'と考えてもよい。あるいは、より特定の範囲のデータを追跡するためのクッキー戦略を使用することもできます。
lastMutationIdChangesは、各クライアントの最後にサーバーで適用されたミューテーションIDを表す値です。この値より小さい mutationID を持つ mutation は、すべて pending ではなく confirmed と見なすべきです。
Rebaseクライアントがプルを受け取ったら、ローカルの状態にパッチを適用する必要があります。しかし、pending mutationが現在ローカル状態に影響を与えているので、ローカル状態にすぐにパッチを適用することはできません。代わりに、ローカルのペンディングミューテーションを元に戻し、プルとして受け取ったパッチを最初に適用した後、再びローカルのペンディングミューテーションを適用します。
リベースしながら発生する可能性のあるコンフリクトは、以下から別々に調べる。
Poke
Pokeは、上記のように、サーバーがクライアントにプルをするように指示するヒントメッセージです。
Replicacheのような分散システムでは、Merge conflictは避けられません。プルとプッシュプロセスでマージが必要です。マージは、マージ結果が予測可能でなければならず、アプリの目的に合った方法で行われるべきです。
もし会議室予約アプリであれば、コンフリックが発生したときに1つの要求のみ承認されなければならない。そのため、まず予約したクライアントのみを承認するマージ方法を採用しなければならない。
逆にTodoアプリなら、ツーリストは同時に追加が起こっても、両方の変更が承認されることが目的に合います。Merge Conflictは、次の2つの状況で発生します。
Rebaseするとき。やはり適用する時の状態が異なることがあるからだ。
以上がレプリカッシュの全体像の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。