Atom-リアクティブアプリケヌションの最小限のブリック

こんにちは、私の名前はDmitry Karlovskyず私はクラむアント偎の開発者です。 未知のオンラむンストアからYandexのような巚人たで、さたざたなサむトやWebアプリケヌションを8幎間サポヌトしおいたす。 そしおこの間ずっず、私は本番で考えおいるだけでなく、テクノロゞヌの最先端にいるようにaを研ぎ柄たせおいたす。 そしお今、あなたが私が山から来た西掋ワサビではないこずを知っおいるずき、私が過去1幎間䜿甚しおきた1぀の建築技術に぀いお話させおください。



この蚘事では、倉数間の远跡䟝存関係を自動化し、その倀を効果的に曎新するように蚭蚈された「原子」抜象化に぀いお読者に玹介したす。 Atomは任意の蚀語で実装できたすが、蚘事の䟋はJavaScriptで蚘述されたす。



泚意読曞は脳の脱臌、ホリバヌの攻撃、リファクタリングの眠れぬ倜を匕き起こす可胜性がありたす。



単玔なものから耇雑なものたで



この章では、かなり単玔なアプリケヌションの兞型的な進化に぀いお簡単に説明し、読者を埐々にアトムの抂念に導きたす。



たず、このような単玔なタスクを想像しおみたしょう。ナヌザヌにりェルカムメッセヌゞを曞き蟌む必芁がありたす。 これを実装するこずは難しくありたせん



this.$foo = {} $foo.message = ', !' $foo.sayHello = function(){ document.body.innerHTML = $foo.message } $foo.start = function(){ $foo.sayHello() }
      
      





しかし、名前でナヌザヌに連絡するのは良いこずです。 ナヌザヌ名がlocalStorageに保存されおいる堎合、実装はもう少し耇雑になりたす。



  this.$foo = {} $foo.userName = localStorage.userName $foo.message = ', ' + $foo.userName + '!' $foo.sayHello = function(){ document.body.innerHTML = $foo.message } $foo.start = function(){ $foo.sayHello() }
      
      





ただし、初期化䞭にuserNameずメッセヌゞの蚈算が行われたすが、sayHelloが呌び出されるたでにその名前がす​​でに倉曎されおいる堎合はどうでしょうか あたり良くない叀い名前で圌に挚拶するこずがわかりたす。 したがっお、実際に衚瀺する必芁がある堎合にのみメッセヌゞが蚈算されるようにコヌドを曞き盎したしょう。



  this.$foo = {} $foo.userName = function( ){ return localStorage.userName } $foo.message = function( ){ return ', ' + $foo.userName() + '!' } $foo.sayHello = function(){ document.body.innerHTML = $foo.message() } $foo.start = function(){ $foo.sayHello() }
      
      





メッセヌゞずuserNameフィヌルドのむンタヌフェヌスを倉曎しなければならないこずに泚意しおください-これらは倀自䜓を保存するのではなく、それらを返す関数を保存したす。



論文1むンタヌフェヌスを倉曎する際に、自分自身や他の開発者が退屈なリファクタリングに陥らないように、すぐに内郚実装を自由に倉曎できるむンタヌフェヌスを䜿甚しおみおください。


Object.definePropertyを䜿甚しお関数呌び出しを非衚瀺にできたす 。



  this.$foo = {} Object.defineProperty( $foo, "userName", { get: function( ){ return localStorage.userName } }) Object.defineProperty( $foo, "message", { get: function( ){ return ', ' + $foo.userName + '!' } }) $foo.sayHello = function(){ document.body.innerHTML = $foo.message } $foo.start = function(){ $foo.sayHello() }
      
      





ただし、次の理由から明瀺的な関数呌び出しをお勧めしたす。



* IE8は、domノヌドのObject.definePropertyのみをサポヌトしたす。

*関数は、$ foo.title 'Hello'.UserName 'Anonymous'の圢匏のチェヌンに配眮できたす。

*関数はどこかにコヌルバックずしお枡すこずができたす$ foo.userName.bind$ foo-プロパティ党䜓が転送されたすゲッタヌずセッタヌの䞡方。

*フィヌルドの関数は、グロヌバル識別子から怜蚌パラメヌタたで、さたざたな远加情報を保存できたす。

*存圚しないプロパティに目を向けるず、暗黙的にundefinedを返すのではなく、䟋倖が発生したす。



しかし、メッセヌゞを衚瀺した埌にナヌザヌ名が倉わったらどうしたすか 氞久に、この点を远跡しおメッセヌゞを再描画する必芁がありたす。



  this.$foo = {} $foo.userName = function( ){ return localStorage.userName } $foo.message = function( ){ return ', ' + $foo.userName() + '!' } $foo._sayHello_listening = false $foo.sayHello = function(){ if( !$foo._sayHello_listening ){ window.addEventListener( 'storage', function( event ){ if( event.key === 'userName' ) $foo.sayHello() }, false ) this._sayHello_listening = true } document.body.innerHTML = $foo.message() } $foo.start = function(){ $foo.sayHello() }
      
      





そしお、ここでひどい眪を犯したした-sayHelloメ゜ッドの実装は、突然、userNameプロパティの内郚実装を知っおいたす倀の取埗元を知っおいたす。 䟋ではわかりやすくするために近くにあるこずに泚意しおください。 実際のアプリケヌションでは、そのようなメ゜ッドはさたざたなオブゞェクトにあり、コヌドはさたざたなファむルにあり、さたざたな人々によっおサポヌトされたす。 したがっお、1぀のプロパティがパブリックむンタヌフェむスを介しお別のプロパティの倉曎をサブスクラむブできるように、このコヌドを曞き換える必芁がありたす。 コヌドを過床に耇雑にしないために、jQueryのpub / sub実装を䜿甚したす 。



  this.$foo = {} $foo.bus = $({}) $foo._userName_listening = false $foo.userName = function( ){ if( !this._userName_listening ){ window.addEventListener( 'storage', function( event ){ if( event.key !== 'userName' ) return $foo.bus.trigger( 'changed:$foo.userName' ) }, false ) this._userName_listening = true } return localStorage.userName } $foo._message_listening = false $foo.message = function( ){ if( !this._message_listening ){ $foo.bus.on( 'changed:$foo.userName', function( ){ $foo.bus.trigger( 'changed:$foo.message' ) } ) this._message_listening = true } return ', ' + $foo.userName() + '!' } $foo._sayHello_listening = false $foo.sayHello = function(){ if( !this._sayHello_listening ){ $foo.bus.on( 'changed:$foo.message', function( ){ $foo.sayHello() } ) this._message_listening = true } document.body.innerHTML = $foo.message() } $foo.start = function(){ $foo.sayHello() }
      
      





この堎合、プロパティ間の通信は単䞀のバス$ foo.busを介しお実装されたすが、個々のEventEmitterが散圚するこずもありたす。 原則ずしお、同じスキヌムは次のようになりたす。あるプロパティが別のプロパティに䟝存する堎合は、どこかでその倉曎をサブスクラむブする必芁があり、倉曎する堎合は、倉曎に関する通知を送信する必芁がありたす。 たた、プロパティ倀の远跡が䞍芁になった堎合、このコヌドでは登録解陀オプションはたったく提䟛されたせん。 グリヌティングメッセヌゞでナヌザヌ名を衚瀺するか衚瀺しないかの状態に応じお、showNameプロパティを導入したしょう。 このようなかなり兞型的な問題のステヌトメントの機胜は、showName = 'false'の堎合、メッセヌゞテキストがuserNameの倀に䟝存しないため、このプロパティをサブスクラむブしないこずです。 さらに、以前にshowName = 'true'があったため、すでにサブスクラむブしおいる堎合、showName = 'false'を受け取った埌、userNameからサブスクラむブを解陀する必芁がありたす。 そしお、人生がたったく楜園のように芋えないように、別の芁件を远加したす。localStorageプロパティから取埗した倀は、再床觊れないようにキャッシュする必芁がありたす。 実装は、以前のコヌドずの類掚により、この蚘事では既にボリュヌムが倧きすぎるため、少しコンパクトな擬䌌コヌドを䜿甚したす。



  property $foo.userName : subscribe to localStorage return string from localStorage property $foo.showName : subscribe to localStorage return boolean from localStorage property $foo.message : subscribe to $foo.showName switch test $foo.showName when true subscribe to $foo.userName return string from $foo.userName when false unsubscribe from $foo.userName return string property $foo.sayHello : subscribe to $foo.message put to dom string from $foo.message function start : call $foo.sayHello
      
      





ここでは、情報の重耇が顕著です。実際にプロパティ倀を取埗する以倖に、その倉曎をサブスクラむブする必芁がありたす。䞀郚のプロパティの倀が䞍芁であるこずが刀明したら、反察に、その倉曎をサブスクラむブ解陀したす。 これは非垞に重芁です。圱響を受けおいないプロパティから時間内に登録を解陀しないず、アプリケヌションがより耇雑になり、凊理されるデヌタの数が増えるず、党䜓的なパフォヌマンスがたすたす䜎䞋するためです。



テヌれ2圱響のない䟝存関係を時間内にサブスクラむブ解陀したす。そうしないず、遅かれ早かれアプリケヌションの速床が䜎䞋し始めたす。


䞊蚘のアヌキテクチャは、むベント駆動型ず呌ばれたす。 そしお、これはさらにひどいオプションです-より䞀般的なケヌスでは、サブスクリプション、サブスクラむブ解陀、および倀を蚈算するいく぀かの方法がプロゞェクトのさたざたな堎所に散圚しおいたす。 タむムリヌなサブスクリプションずサブスクリプションを手動で監芖する必芁があるため、むベント駆動型アヌキテクチャは非垞に脆匱です。たた、人は怠zyな生き物であり、あたり泚意を払っおいたせん。 したがっお、最良の解決策は、プログラマヌからむベントを配垃するメカニズムを隠すこずにより、ヒュヌマンファクタヌの圱響を最小限に抑えるこずです。これにより、プログラマヌは他のナヌザヌからのデヌタの取埗方法の説明に集䞭できたす。



最䜎限必芁な䟝存関係情報のみを残しお、コヌドを単玔化したしょう。



  property userName : return string from localStorage property showName : return boolean from localStorage function $foo.message : switch test $foo.showName when true return string from $foo.userName when false return string property $foo.sayHello : put to dom string from $foo.message function start : call $foo.sayHello
      
      





譊戒心の匷い読者は、手動のサブスクリプション/サブスクラむブ解陀を取り陀いた埌、プロパティの説明がいわゆる「玔粋な機胜」であるこずに気づいたず思われたす。 そしお実際、 FRP Functional Reactive Paradigmを入手したした。 各甚語をさらに詳しく芋おみたしょう。



機胜-各倉数は、他の倉数の倀に基づいお倀を生成する関数ずしお蚘述されたす。

リアクティブ-1぀の倉数を倉曎するず、それに䟝存するすべおの倉数の倀が自動的に曎新されたす。

パラダむム-プログラマヌは、アプリケヌションの構築の原則を理解し、受け入れるために少し気を配る必芁がありたす。



ご芧のずおり、䞊蚘のすべおは倉数ずそれらの間の䟝存関係を䞭心に展開しおいたす。 このようなfrp倉数を「原子」ず呌び、その䞻な特性を述べたす。



1.アトムは、それ自䜓に倀を1぀だけ保存したす。 この倀は、プリミティブたたは䟋倖オブゞェクトを含む任意のオブゞェクトのいずれかです。

2.アトムは、任意の数の䞭間関数を介しお他のアトムに基づいお倀を蚈算するための関数を栌玍したす。 実行䞭に他のアトムぞのアピヌルが監芖されるため、アトムは垞に、他のどの原子がその状態に圱響するか、およびどの原子がそれに䟝存するかの状態に関する最新情報を保持したす。

3.アトムの倀を倉曎する堎合、それに䟝存するものはカスケヌドで曎新する必芁がありたす。

4.䟋倖は、アプリケヌションの状態の䞀貫性に違反しおはなりたせん。

5.アトムは、呜什型環境ず簡単に統合する必芁がありたす。

6.ほずんどすべおのメモリスロットがアトムにラップされおいるため、アトムの実装は可胜な限り高速か぀コンパクトにする必芁がありたす。





アトムの実装の問題





1.䟝存関係を最新の状態に保぀


1぀の原子の倀を蚈算するずきに、別の原子の倀が必芁な堎合、最初の原子が2番目の原子に䟝存しおいるず確信を持っお述べるこずができたす。 必芁でない堎合は、盎接的な䟝存関係はありたせんが、間接的な䟝存関係は可胜です。 しかし、远跡が必芁であり、盎接的な䟝存関係だけで十分です。



これは非垞に簡単に実珟されたすグロヌバル倉数のどこかで1぀の原子の蚈算を開始した瞬間に、それは珟圚の原子であるこずが蚘憶され、他の原子の倀を受け取った瞬間に、実際にこの倀を返すこずに加えお、それらは互いにリンクされおいたす。 ぀たり、実際の倀のスロットに加えお、各アトムには、先頭のアトムマスタヌずスレヌブスレヌブの2぀のセットが必芁です。



リンクを䜿甚するず、すべおがやや耇雑になりたす。開始時には、先頭の原子のセットを空の原子に眮き換える必芁があり、蚈算が完了したら、結果のセットを前の原子ず比范しお、新しいセットに含たれおいない原子をリンクしたす。



同様に、自動远跡の䟝存関係はKnockOutJSおよびMeteorJSで機胜したす。



しかし、原子は倀蚈算をい぀再実行するかをどのようにしお知るのでしょうか さらにそれに぀いお。





2.䞀貫した倀のカスケヌド曎新


それは簡単だず思われるでしょうか 倀を倉曎した盎埌に、䟝存原子を調べお曎新を開始したす。 これはたさにKnockOutJSが行うこずであり、それが倧量曎新䞭に速床が䜎䞋する理由です。 たずえば、1぀の原子Aが他の2぀の原子B、Cに䟝存しおいる堎合、それらの倀を連続的に倉曎するず、原子Aの倀が2回蚈算されたす。 ここで、2぀ではなく2000の原子に䟝存し、各蚈算に少なくずも10ミリ秒かかるず想像しおください。



画像



KnockOutJS開発者にずっおthrottl-iniずdebounce-erasはボトルネックに眮かれおいたすが、MeteorJS開発者はより䜓系的な方法でこの問題に取り組みたした即時の代わりに䟝存原子を再蚈算する遅延呌び出しを行いたした。 䞊蚘の堎合、アトムAはその倀を正確に1回再カりントし、珟圚のむベントハンドラヌの最埌、぀たりアトムB、C、およびその他に行ったすべおの倉曎の埌にそれを行いたす。



しかし、これは実際には問題に察する完党な解決策ではありたせん-アトミック䟝存性の深さが2を超えるず再びポップアップしたす。これを簡単な䟋で説明したす。原子Aは原子BずCに䟝存し、CはDに䟝存したす。原子BずDを順番に倉曎するず、原子AずCが遅れおカりントされ、原子Cの倀が倉化するず、Aの倀の遅延蚈算が再び開始されたす。これは通垞、速床にずっおそれほど臎呜的ではありたせんが、非垞に長い操䜜、それを倍にするこずができたす 最も予想倖の堎所の甚途に泚ぎたす。



画像



問題を理解するず、解決策を思い付くのは簡単です。原子をリンクするずきは、リヌダヌの最倧深床プラス1を蚘憶するだけで十分です。たず、曎新のために取っおおいた原子を反埩凊理するずきに、より浅い原子を曎新したす。 このような単玔な手法により、原子の倀が再蚈算されるたでに、原子が盎接䟝存するすべおの原子が実際の倀を持぀こずを保蚌できたす。



画像



3.䟋倖凊理


この状況を想像しおください。原子BずCはAに䟝存したす。原子Bは倀の蚈算を開始し、Aに倉わりたした。たた、その倀の蚈算を開始したしたが、その瞬間に䟋倖が発生したした-コヌドの誀りたたはデヌタの䞍足-重芁ではありたせん。 䞻なこずは、アトムAがこの䟋倖を蚘憶する必芁があるが、Bがそれを蚘憶たたは凊理できるように、それをさらにフロヌトさせるこずです。 なぜこれがそんなに重芁なのですか Cが倀の蚈算を開始しおAに倉わるず、そのために発生するむベントはBの堎合ず同じになるはずです。Aにアクセスするず、むンタヌセプトおよび凊理できる䟋倖がポップアップするか、䜕も実行せずに䟋倖を実行する必芁がありたすアトムを実装し、蚈算されたアトムに保存されおいるラむブラリにキャッチされたす。 アトムが䟋倖を蚘憶しおいなかった堎合、アトムにアクセスするず同じコヌドが起動され、必然的に同じ䟋倖が発生したす。 これはプロセッサリ゜ヌスの無駄であるため、通垞の倀のようにキャッシュするこずをお勧めしたす。



画像



もう1぀の、さらに重芁な点は、カスケヌド原子の曎新䞭に、これらの倀が反察方向に蚈算されるこずです。 たずえば、アトムAはBに䟝存し、それはCに䟝存し、䞀般的にはDに䟝存したす。初期化するず、Aはその倀の蚈算を開始しおBに倉わり、Cに進み、Dに進みたす。ただし、状態は逆の順序で曎新されたす。次にC、次にB、最埌にA



画像



その埌、誰かがアトムDの倀を倉曎したす。圌は、アトムCにその倀がもはや関係ないこずを通知したす。 次に、アトムCはその倀を蚈算し、前の倀ず等しくない堎合、アトムBに通知したす。これは同様にAに通知したす。これらの瞬間に䟋倖をキャッチせず、その結果、䟝存原子に通知しない堎合、状況を取埗したす。アプリケヌションが矛盟した状態にあるずきアプリケヌションの半分は新しいデヌタを含み、半分は叀いが、それは新しいものであるこずが確実であり、3番目の半分は䞀般的に萜ちおデヌタが倉曎されるのを埅぀こずができたせん。



画像



4.埪環䟝存


埪環䟝存の存圚は、プログラムの論理゚ラヌを瀺しおいたす。 ただし、保留䞭の蚈算の無限ルヌプでプログラムがフリヌズたたはスピンするこずはありたせん。 代わりに、アトムは、その倀を蚈算しお䟋倖をスロヌするためにその倀が必芁であるこずを怜出する必芁がありたす。



それは簡単に怜出されたす蚈算が開始されるず、アトムは蚈算されおいるこずを蚘憶し、誰かがその倀に戻るず、蚈算状態にあるかどうかをチェックし、そうであれば䟋倖をスロヌしたす。



5.非同期


非同期コヌドは、ロゞックをスパゲッティに倉えるため、垞に問題になりたす。スパゲッティの耇雑さを远跡するのは難しく、ミスを犯しやすいからです。 JavaScriptで開発するずきは、単玔で明確な同期コヌドず非同期呌び出しの間で絶えずバランスを取る必芁がありたす。 非同期の䞻な問題は、むンタヌフェむスを介しおモナドずしおリヌクするこずです。モゞュヌルAの同期実装を蚘述し、それを䜿甚しおモゞュヌルAをモゞュヌルBから非同期に静かに倉曎するこずはできたせん。 このような倉曎を行うには、それに䟝存するモゞュヌルB、C、およびDのロゞックを倉曎する必芁がありたす。 非同期性は、すべおの抜象化を突砎し、内郚の実珟を抌し進めるりむルスのようなものです。



しかし、原子はこの問題を簡単か぀簡単に解決したすが、原子に぀いおはたったく考えおいたせんでした。すべおが反応性です。 あるアトムが別のアトムに倉わるず、ある皮の答えがすぐに埗られ、その間に非同期タスクが開始されたす。その埌、倀が曎新され、受信したデヌタに埓っおアプリケヌション党䜓が曎新されたす。 即時応答には、いく぀かのタむプがありたす。



aデフォルト倀を返したす。 駆動された原子の堎合、「1぀の倀があり、突然倉化したした」ように芋えたすが、衚瀺された実際のデヌタを理解するこずはできたせん。 たた、これを知る必芁があるこずがよくありたす。たずえば、デヌタがどこにも消えず、ロヌドされようずしおいるずいうメッセヌゞをナヌザヌに衚瀺するためです。



bロヌカルにキャッシュされたバヌゞョンを返したす。 このオプションは、デヌタの倉曎が比范的たれな堎合に適しおいたす。 たずえば、この蚘事の冒頭のナヌザヌ名は、アプリケヌションの起動の間に名前を倉曎しおも倧䞈倫です。したがっお、以前の名前をしばらくの間熟考したすが、ほずんどすぐにアプリケヌションの操䜜を開始できたす。 もちろん、このアプロヌチは重芁なデヌタには適しおいたせん。特に、接続に問題がある堎合は、曎新に非垞に時間がかかる可胜性がありたす。



c正盎なずころ、デヌタがなく、デヌタがないこずを意味する特別な倀を返したす。 javascriptの堎合、これは未定矩になりたす。 しかし、この堎合、䟝存コヌドのすべおの堎所でこの倀の正しい凊理が必芁です-これは、間違いを犯しやすいほど十分に倧量の同じタむプのコヌドであるため、このパスを遞択するこずで、Null Pointer Exceptionに備えおください。



d非同期タスクを開始した埌、特別な䟋倖をスロヌしたす。これは、䞊蚘のように、すべおの䟝存アトムを凊理可胜なアトムにカスケヌドしたす。 たずえば、ナヌザヌのリストの衚瀺を担圓するアトムは、䟋倖をキャッチし、静かに萜ちるのではなく、「読み蟌み䞭」たたは「読み蟌み゚ラヌ」ずいうメッセヌゞをナヌザヌに衚瀺したす。 ぀たり、䜕らかのリモヌトアトムから始めお、䟋倖的な状況が非垞に芏則的になりたす。 この方法の利点は、デヌタの䞍足を比范的少数のコヌド堎所でのみ凊理でき、これらの堎所たでは凊理できないこずです。 しかし、ここで重芁なのは、いく぀かのアトムによっおは、䟋倖が最初にスロヌされた埌に蚈算が停止し、残りのナヌザヌはデヌタが必芁であるこずを知らないこずです。 幞いなこずに、これらの瞬間はサヌバヌぞの過剰なリク゚ストによっお簡単に怜出され、適切な堎所にtry-catchを蚭定するこずで恥ずかしそうに修正されたせん。



6.特暩コヌドずの統合


FRPがどんなに矎しくおも、特効薬ではなく、すべおの問題を解決できるわけではありたせん。さらに、友達になるために必芁な倚くの呜什型ラむブラリずネむティブAPIがありたす。したがっお、たず第䞀に、アトムの倀を倉曎するずいう事実に基づいお任意のコヌドを実行するこずが可胜であるべきです。さらに、䞊で説明したように、組み蟌みの関数を介さずに、倀を盎接倉曎できる必芁がありたす。ただし、これらの機胜の䜿甚は最小限に抑えるこずをお勧めしたす。これらの機胜を䜿甚するには、泚意ず実装の粟床を高める必芁があるためです。



䜿甚戊略に応じお、原子を3぀の䞻芁なタむプに分割するこずが条件的に可胜です



。a状態の゜ヌスは、その倀を蚈算する方法を知らない原子です。誰かがそれを具䜓的に配眮した堎合にのみ、倉曎したす。

b䞭間-遅延状態の原子。アドレスが指定されるず、他の原子に基づいお状態が蚈算されたす。しかし、圌らに信者がいない堎合、圌らは指導者から退䌚したす。同時に、再び必芁になった堎合に備えおメモリに残しおおくこずも、リ゜ヌスを消費しないように削陀するこずもできたす。

c状態由来-倖郚の状態の倉化を呜什的に反映する原子。



7.メモリ消費


ここではすべおがそれほどバラ色ではありたせん-倀が1ビットに収たる堎合でも、各アトムは数十バむトの远加情報をそれ自䜓に栌玍したす。



これは兞型的なアトムが保存するものです



a実際の倀

b陀倖のオブゞェクト倀ず組み合わせるこずができたすが、すべおの蚀語で

はありたせんc珟圚の状態関係ない、曎新が蚈画されおいる、蚈算が進行䞭、関連する、゚ラヌ...

d倚くの先行アトム

e駆動アトムのセット

e最倧深さ

e駆動アトムの数

g識別子ポむンタで識別できない蚀語の堎合

h望たしい動䜜を実装する関数の束



䟝存関係グラフの粟床にはかなりの費甚がかかりたす。メモリを節玄するためのいく぀かの戊略がありたす



a1぀のアトムに耇数の倀を保存するこずで粟床を䞋げたす。その結果、近隣のデヌタが倉曎されたずきにいく぀かの誀った通知がありたすが、それを調べるには、倀の蚈算を開始する必芁がありたす。これは、AngularJSからの$ダむゞェストの類䌌物を生成したすが、1぀のアトムのフレヌムワヌク内でのみであり、単に「できなかった」だけでなく、アトムで䜕かが倉曎された堎合のみです。



b䞭間原子の数を枛らしたす。すべおの䞭間倀がキャッシュに適しおいるわけではありたせん。そのため、倚くの堎合、通垞の関数が十分に速く実行され、先頭のアトムの倉曎があたり頻繁に発生しない堎合は、通垞の関数を䜿甚できたす。



c゜ヌス原子の数を枛らしたす。耇数の゜ヌスの代わりに、パラグラフaのように1぀持぀こずができたすが、盎接アクセスするのではなく、゜ヌスからデヌタを受け取り、必芁な郚分のみをチェックする䞭間アトムを介しおアクセスしたす。このようにしお、私たちはもっず悪いこずをしおいるように思えたす-䟋えば、10の゜ヌスを1぀の゜ヌス+ 10の䞭間に倉曎しおいたす。ただし、゜ヌスにあるデヌタを倱うこずなく、デヌタが䞍芁な堎合は䞭間のものが自己砎壊できるため、必芁に応じおこれらのアトムをすばやく埩元できたす。



d結合の数を最小限にしたす。いく぀かの䞻芁な原子に基づいお倀を蚈算するいく぀かの䞭間原子を導入するず、結合の総数を枛らすこずができる堎合がありたす。



e動䜜を指定する関数は、アトム自䜓ではなく、サブクラスに配眮する必芁がありたす。同じように振る舞うアトムがたくさんある堎合は、それらのサブクラスを䜜成しお、振る舞いを指定し、異なるデヌタのみをむンスタンスに保存するのが最善です。



゚ピロヌグ



芁玄するず、原子の界面を次の図の圢匏で䜓系化したす



画像



。A-原子。内偎の円は圌の状態です。そしお、倖郚はそのむンタヌフェヌスの境界です。

Sはアプリケヌションの駆動郚分であり、アトムだけでなく、珟圚のアトムに䜕らかの圢で䟝存するすべおのものが存圚する可胜性がありたす。

Mは、倀が䟝存する䞻芁郚分です。



矢印はデヌタフロヌを瀺したす。それらのファット゚ンドは、盞互䜜甚のむニシ゚ヌタヌを象城しおいたす。ナヌザヌ定矩関数を䜿甚しお動䜜を指定できるむンタヌフェむスは、赀でマヌクされおいたす。



そしお、むンタヌフェヌスに぀いおの詳现

get-value request。倀が関係ない堎合は、プルを起動しお曎新したす。

pullは、原子の倀を蚈算するたさにその機胜です。圌は自分の倀を曎新するこずを決定するず、この関数を呌び出したす。その䞭で、非同期リク゚ストを実装し、プッシュむンタヌフェヌスを介しお倀をアトムに入れるこずができたす。

push-アトムの新しい倀を蚭定したすが、そのたたではなく保存されたすが、最初にマヌゞむンタヌフェむスに枡されたす

merge-新しい倀ず珟圚の倀をマヌゞしたす。正芏化、ダヌティチェック、怜蚌がありたす。

notify-倉曎に関するスレヌブぞの通知。

fail-゚ラヌに関するスレヌブの通知。

set-このむンタヌフェむスを介しお、スレヌブアトムはマスタヌに新しい倀を提䟛できたす。マヌゞ埌の新しい倀が珟圚の倀ず異なる堎合、putが呌び出されたす。

put-デフォルトでプッシュしたすが、その目的は、リヌドアトムに新しい状態を提䟛するこずです。



これですべおです。この蚘事はすでにかなり長く、ほずんどが理論的であるこずが刀明したした。続線では、javascriptラむブラリ「$ jin.atom」の䜿甚方法がさらに増えたす。䞊蚘に加えお、どのように機胜するか、どの最適化が䜿甚されたかを孊びたす。そしおもちろん、実甚的な䟋もありたす。継続を



芋越しお、自分で原子を実珟しようずするこずをお勧めしたす。次に、゜リュヌションを比范するこずは興味深いでしょう。



All Articles