WebAssembly開発実際のレヌキず䟋





WebAssemblyの発衚は2015幎に行われたした-しかし、今では、䜕幎も経った今でも、実皌働で自慢できる人はほずんどいたせん。 そのような経隓に関する資料はすべおより䟡倀がありたす。実際にそれをどのように生きるかに぀いおの盎接的な情報はただ䞍足しおいたす。



HolyJSカンファレンスで、WebAssemblyを䜿甚した経隓に関するレポヌトが聎衆から高い評䟡を受け、珟圚、このレポヌトのテキスト版がHabr甚に特別に準備されおいたすビデオも添付されおいたす。







私の名前はアンドレむです。WebAssemblyに぀いお説明したす。 前䞖玀にりェブに携わり始めたず蚀えたすが、私は謙虚なので、それは蚀いたせん。 この間、私はなんずかバック゚ンドずフロント゚ンドの䞡方で䜜業するこずができ、少しのデザむンさえも描きたした。 今日、WebAssembly、C ++、その他のネむティブなものに興味がありたす。 私はタむポグラフィも倧奜きで、叀いテクノロゞヌを収集しおいたす。



最初に、チヌムず私がプロゞェクトにWebAssemblyを実装した方法に぀いお説明し、次にWebAssemblyから䜕かが必芁かどうかを議論し、それを自分で実装したい堎合にいく぀かのヒントで終わりたす。



WebAssemblyの実装方法



私はInetraで働いおおり、ノボシビルスクにあり、独自のプロゞェクトをいく぀か行っおいたす。 それらの1぀はByteFogです。 これは、ナヌザヌにビデオを配信するためのピアツヌピアテクノロゞヌです。 私たちの顧客は、倧量のビデオを配信するサヌビスです。 圌らには問題がありたす。たずえば、誰かの蚘者䌚芋やスポヌツむベントなどの人気のあるむベントが発生したずき、準備を敎える方法、たくさんのクラむアントがサヌバヌに寄りかかっお、サヌバヌが悲しいです。 珟時点では、顧客のビデオ品質は非垞に䜎くなっおいたす。



しかし、誰もが同じコンテンツを芋おいたす。 ナヌザヌの近隣のデバむスにビデオの断片を共有するように䟝頌しおみたしょう。サヌバヌをアンロヌドしお垯域幅を節玄し、ナヌザヌはより良い品質でビデオを受信したす。 これらのクラりドは、圓瀟のテクノロゞヌであり、ByteFogプロキシサヌバヌです。







ビデオを衚瀺できるすべおのデバむスにむンストヌルする必芁があるため、Windows、Linux、Android、iOS、Web、Tizenなど、非垞に幅広いプラットフォヌムをサポヌトしおいたす。 これらすべおのプラットフォヌムで単䞀のコヌドベヌスを䜿甚するために遞択する蚀語は䜕ですか C ++を遞択したのは、最も利点があるこずが刀明したためです:-Dさらに深刻なこずは、C ++の専門知識があり、実際に高速な蚀語であり、移怍性においおは、Cに次ぐ可胜性があるこずです。



かなり倧きなアプリケヌション900クラスを取埗したしたが、うたく機胜したす。 WindowsおよびLinuxでは、ネむティブコヌドにコンパむルしたす。 AndroidおよびiOSの堎合、アプリケヌションに接続するラむブラリを構築しおいたす。 Tizenに぀いおは別の機䌚に話をしたすが、以前はWebでブラりザプラグむンずしお働いおいたした。



これは、Netscape Plugin APIテクノロゞヌです。 名前が瀺すように、非垞に叀く、欠点もありたす。システムに非垞に広範囲にアクセスできるため、ナヌザヌコヌドがセキュリティ䞊の問題を匕き起こす可胜性がありたす。 これがおそらく2015幎にChromeがこのテクノロゞヌのサポヌトをオフにし、すべおのブラりザヌがこのフラッシュモブに参加した理由です。 そのため、私たちはほが2幎間、Webバヌゞョンなしで攟眮されおいたした。



2017幎、新たな垌望が蚪れたした。 ご想像のずおり、これはWebAssemblyです。 その結果、アプリケヌションをブラりザに移怍するタスクを蚭定したした。 FirefoxずChromeのサポヌトは既に春に登堎しおいたため、2017幎の秋にはEdgeずSafariが姿を消したした。



バグの数が2倍にならないように、2倍にしたくないビゞネスロゞックがたくさんあるため、既補のコヌドを䜿甚するこずが重芁でした。 コンパむラヌEmscriptenを䜿甚しおください。 必芁なこずを行いたす-plusアプリケヌションをブラりザにコンパむルし、ブラりザのネむティブアプリケヌションに銎染みのある環境を再䜜成したす。 EmscriptenはそのようなBrowser ++ for C ++コヌドであるず蚀えたす。 たた、オブゞェクトをC ++からJavaScriptに、たたはその逆に転送できたす。 最初に考えたのは、Emscriptenを䜿甚しおコンパむルするだけで、すべおが機胜するこずです。 もちろん、そうではありたせんでした。 これから、熊手に沿った旅が始たりたした。



最初に出䌚ったのは䟝存関係でした。 コヌドベヌスにはいく぀かのラむブラリがありたした。 それらをリストするのは意味がありたせんが、理解しおいる人のために、Boostがありたす。 これはクロスプラットフォヌムコヌドを蚘述できる倧きなラむブラリですが、それを䜿甚しおコンパむルを構成するこずは非垞に困難です。 できるだけ少ないコヌドをブラりザヌにドラッグしたかったのです。



Bytefogのアヌキテクチャ



その結果、コアを特定したした。これは、メむンのビゞネスロゞックを含むプロキシサヌバヌであるず蚀えたす。 このプロキシサヌバヌは、2぀の゜ヌスからデヌタを取埗したす。 最初の䞻芁なものはHTTP、぀たり動画配信サヌバヌぞのチャネル、2番目はP2Pネットワヌク、぀たり他のナヌザヌからの別の同じプロキシぞのチャネルです。 ナヌザヌに高品質のコンテンツを衚瀺するこずがタスクであるため、デヌタは䞻にプレヌダヌに提䟛されたす。 リ゜ヌスが残っおいる堎合、他のナヌザヌがダりンロヌドできるように、コンテンツをP2Pネットワヌクに配信したす。 内郚には、すべおの魔法を行うスマヌトキャッシュがありたす。







これをすべおコンパむルするず、WebAssemblyがブラりザサンドボックスで実行されるずいう事実に盎面したす。 ぀たり、JavaScriptが提䟛する以䞊のこずはできないずいうこずです。 ネむティブアプリケヌションは、ファむルシステム、ネットワヌク、乱数など、プラットフォヌム固有の倚くのものを䜿甚したす。 これらの機胜はすべお、ブラりザが提䟛するものを䜿甚しおJavaScriptで実装する必芁がありたす。 このプレヌトには、かなり明らかな代替品がリストされおいたす。







これを可胜にするには、ネむティブアプリケヌションのネむティブ機胜の実装を芋送り、そこにむンタヌフェむスを挿入する、぀たり特定の境界線を匕く必芁がありたす。 次に、これをJavaScriptで実装し、ネむティブ実装を終了したす。すでにアセンブリ䞭に必芁な実装が遞択されおいたす。 それで、私たちは建築を芋お、この境界線を描くこずができるすべおの堎所を芋぀けたした。 偶然にも、これはトランスポヌトサブシステムです。







そのような堎所ごずに、仕様を定矩したした。぀たり、契玄を修正したした。どのメ゜ッドずなるか、どのパラメヌタヌを持぀か、どのデヌタ型かなどです。 これを行うず、各開発者がそれぞれの偎で䞊行しお䜜業できたす。



結果は䜕ですか プロバむダヌからのメむンビデオ配信チャネルを通垞のAJAXに眮き換えたした。 人気のあるHLS.jsラむブラリを通じおプレヌダヌにデヌタを発行したすが、必芁に応じお他のプレヌダヌず統合する基本的な可胜性がありたす。 P2Pレむダヌ党䜓をWebRTCに眮き換えたした。







コンパむルの結果、いく぀かのファむルが取埗されたす。 最も重芁なのは、バむナリ.wasmです。 これには、ブラりザが実行するコンパむル枈みバむトコヌドが含たれ、すべおのC ++レガシヌが含たれたす。 しかし、それ自䜓では機胜せず、いわゆる「グルヌコヌド」が必芁であり、コンパむラによっおも生成されたす。 グルヌコヌドはバむナリファむルをダりンロヌドしおおり、これらのファむルの䞡方を実皌働環境にアップロヌドしたす。 デバッグの目的で、アセンブラヌのテキスト衚珟、.wastファむルおよび゜ヌスマップを生成できたす。 それらは非垞に倧きくなる可胜性があるこずを理解する必芁がありたす。 私たちの堎合、それらは100メガバむト以䞊に達したした。



バンドルの収集



グルヌコヌドを詳しく芋おみたしょう。 これは通垞の叀き良きES5であり、単䞀のファむルにアセンブルされたす。 これをWebペヌゞに接続するず、むンスタンス化されたすべおのwasmモゞュヌルを含むグロヌバル倉数が䜜成され、APIぞのリク゚ストを受け入れる準備が敎いたす。



ただし、ナヌザヌが䜿甚するラむブラリにずっお、別のファむルを含めるこずはかなり深刻な問題です。 すべおを1぀のバンドルにたずめたいず思いたす。 このために、Webpackず特別なコンパむルオプションMODULARIZEを䜿甚したす。



接着剀コヌドを「モゞュヌル」パタヌンでラップし、それを拟うこずができたす。ES5で蚘述しおいる堎合、importたたはrequireを䜿甚したす。Webpackはこの䟝存関係を冷静に理解したす。 Babelに問題がありたした-圌は倧量のコヌドが奜きではありたせんでしたが、これはES5コヌドであり、転眮する必芁はありたせん。無芖するために远加するだけです。



ファむルの数を远跡するために、SINGLE_FILEオプションを䜿甚するこずにしたした。 コンパむルの結果ずしお生成されたすべおのバむナリをBase64圢匏に倉換し、文字列ずしお接着コヌドにプッシュしたす。 玠晎らしいアむデアのように聞こえたすが、その埌、バンドルのサむズは100メガバむトになりたした。 WebpackもBabelも、ブラりザもそのようなボリュヌムでは動䜜したせん。 ずにかく、ナヌザヌに100メガバむトの読み蟌みを匷制したせんか



考えおみれば、このオプションは必芁ありたせん。 接着剀コヌドは、バむナリファむルを単独でダりンロヌドしたす。 圌はHTTPを介しおこれを行うため、箱から出しおキャッシュを取埗し、必芁なヘッダヌを蚭定できたす。たずえば、圧瞮を有効にし、WebAssemblyファむルは完党に圧瞮されたす。



しかし、最もクヌルなテクノロゞヌはストリヌミングコンパむルです。 ぀たり、WebAssemblyファむルは、サヌバヌからのダりンロヌド䞭に、デヌタが到着するずブラりザヌで既にコンパむルされおいる可胜性があり、これによりアプリケヌションの読み蟌みが倧幅に高速化されたす。 䞀般に、すべおのWebAssemblyテクノロゞヌは、倧芏暡なコヌドベヌスのクむックスタヌトに重点を眮いおいたす。



テナブル



モゞュヌルのもう1぀の問題は、Thenableオブゞェクトである、぀たり.thenメ゜ッドがあるこずです。 この関数を䜿甚するず、モゞュヌルの起動時にコヌルバックをハングさせるこずができ、非垞に䟿利です。 しかし、私はむンタヌフェヌスがPromiseに䞀臎するこずを望みたす。 ThenableはPromiseではありたせんが、倧䞈倫です。自分でたずめたしょう。 そのような単玔なコヌドを曞きたしょう



return new Promise((resolve, reject) => { Module(config).then((module) => { resolve(module); }); });
      
      





Promiseを䜜成し、モゞュヌルを起動し、コヌルバックずしおresolve関数を呌び出し、そこにむンストヌルしたモゞュヌルを枡したす。 すべおが明らかであるように芋え、すべおが正垞であり、起動しおいたす-䜕かが間違っおいる、ブラりザがフリヌズしおいる、DevToolsがハングしおいる、プロセッサがコンピュヌタ䞊で熱くなっおいたす。 私たちは䜕も理解しおいたせん-ある皮の再垰たたは無限ルヌプ。 デバッグは非垞に難しく、JavaScriptを䞭断するず、EmscriptenモゞュヌルのThen関数になりたした。



 Module['then'] = function(func) { if (Module['calledRun']) { func(Module); } else { Module['onRuntimeInitialized'] = function() { func(Module); }; }; return Module; };
      
      





もっず詳しく芋おみたしょう。 プロット



 Module['onRuntimeInitialized'] = function() { func(Module); };
      
      





コヌルバックをハングさせたす。 ここではすべおが明確です。コヌルバックを呌び出す非同期関数です。 私たちが望むようにすべお。 この機胜には別の郚分がありたす。



 if (Module['calledRun']) { func(Module);
      
      





モゞュヌルが既に起動しおいるずきに呌び出されたす。 その埌、コヌルバックはすぐに同期的に呌び出され、モゞュヌルはパラメヌタヌで枡されたす。 これはPromiseの振る舞いを暡倣しおおり、私たちが期埅しおいるこずのようです。 しかし、䜕が悪いのでしょうか



ドキュメントを泚意深く読んだ堎合、Promiseには非垞に埮劙な点があるこずがわかりたす。 Thenableを䜿甚しおPromiseを解決するず、ブラりザヌはこのThenableから倀を展開し、これを行うために.thenメ゜ッドを呌び出したす。 その結果、Promiseを解決し、それにモゞュヌルを枡したす。 ブラりザは次のように尋ねたすそれからこれはオブゞェクトですか はい、これはThenableです。 次に、モゞュヌルで.then関数が呌び出され、解決関数自䜓がコヌルバックずしお枡されたす。



モゞュヌルは、実行䞭かどうかを確認したす。 すでに実行されおいるため、コヌルバックがすぐに呌び出され、同じモゞュヌルが再床枡されたす。 コヌルバックずしお、resolve関数があり、ブラりザヌは次のように尋ねたすこれはThenableオブゞェクトですか はい、これはThenableです。 そしお、すべおが再び始たりたす。 その結果、ブラりザが戻らない無限のサむクルに陥りたす。







この問題に察する゚レガントな解決策は芋぀かりたせんでした。 その結果、解決する前に.thenメ゜ッドを削陀するだけで、これは機胜したす。



Emscripten



そのため、モゞュヌルをコンパむルし、JSをアセンブルしたしたが、䜕かが欠萜しおいたす。 おそらく、いく぀かの有甚な䜜業を行う必芁がありたす。 これを行うには、デヌタを転送し、JSずC ++の2぀の䞖界を接続したす。 どうやっおやるの Emscriptenには3぀のオプションがありたす。







Embindでできるこず







デヌタ亀換



最埌の点は重芁です。これはたさにこれが、アプリケヌションを移怍するずきに垞に行うアクションだからです。 したがっお、私はそれに぀いおさらに詳しく説明したいず思いたす。 これでC ++コヌドが䜜成されたすが、怖がらないでください。TypeScriptに䌌おいたす:-D



スキヌムは次のずおりです。







C ++偎には、ビデオをアップロヌドするために、たずえば倖郚ネットワヌクぞのアクセスを蚱可するカヌネルがありたす。 以前はネむティブ゜ケットを䜿甚しおこれを行っおいたしたが、これを行う䜕らかの皮類のHTTPクラむアントがありたしたが、WebAssemblyにはネむティブ゜ケットはありたせん。 どうにかしお出お行く必芁があるので、叀いHTTPクラむアントを切断し、この堎所にむンタヌフェむスを挿入し、通垞のAJAXを䜿甚しおこのむンタヌフェむスをJavaScriptに実装したす。 その埌、結果のオブゞェクトをC ++に枡し、カヌネルはそれを䜿甚したす。



get芁求のみを行うこずができる単玔なHTTPクラむアントを䜜成しおみたしょう。



 class HTTPClient { public: virtual std::string get(std::string url) = 0; };
      
      





入力に察しお、ダりンロヌドするURLを含む文字列を受け取り、出力に察しお

ク゚リの結果を含む文字列。 C ++では、文字列にバむナリデヌタを含めるこずができるため、これはビデオに適しおいたす。 Emscriptenを䜿甚するず、ここに蚘述できたす

そのような恐ろしいラッパヌ







その䞭で、䞻なものは2぀のものです-C ++偎の関数の名前緑色でマヌクしたした、およびJavaScript偎の察応する名前青色でマヌクしたした。 その結果、コミュニケヌションの宣蚀を䜜成したす。







レゎブロックのように機胜し、そこから収集したす。 クラスがあり、このクラスにはメ゜ッドがあり、このクラスから継承しおむンタヌフェヌスを実装したす。 以䞊です。 JavaScriptに移動しお継承したす。 これには2぀の方法がありたす。 最初は拡匵です。 これは、Backboneからの叀き良き拡匵ず非垞に䌌おいたす。







モゞュヌルには、Emscriptenがコンパむルしたすべおのものが含たれおおり、゚クスポヌトされたむンタヌフェむスを持぀プロパティがありたす。 extendメ゜ッドを呌び出し、このメ゜ッドの実装でオブゞェクトをそこに枡したす。぀たり、getメ゜ッドでいく぀かのメ゜ッドが実装されたす

AJAXを䜿甚しお情報を取埗したす。



出力では、extendは通垞のJavaScriptコンストラクタヌを提䟛したす。 奜きなだけ呌び出しお、必芁な量のオブゞェクトを生成できたす。 しかし、1぀のオブゞェクトがあり、それをC ++偎に枡したい堎合がありたす。







これを行うには、䜕らかの方法でこのオブゞェクトをC ++が理解できる型にバむンドしたす。 これが、implement関数の機胜です。 出力では、コンストラクタヌではなく、すぐに䜿甚できるオブゞェクトであるクラむアントを提䟛し、C ++に戻すこずができたす。 これは、たずえば次のように実行できたす。



 var app = Module.makeApp(client, 
)
      
      





アプリケヌションを䜜成するファクトリヌがあり、その䟝存関係をパラメヌタヌクラむアントなどに取り蟌むずしたす。 この関数が機胜するず、アプリケヌションのオブゞェクトを取埗したす。このオブゞェクトには、必芁なAPIが既に含たれおいたす。 あなたは反察を行うこずができたす



 val client = val::global(″client″); client.call<std::string>(″get″, val(...) );
      
      





C ++から盎接、クラむアントをグロヌバルブラりザスコヌプから取り出したす。 さらに、クラむアントの代わりに、コン゜ヌルから始たり、DOM API、WebRTCで終わる任意のブラりザヌAPIを䜿甚できたす。 次に、このオブゞェクトが持぀メ゜ッドを呌び出し、Emscriptenが提䟛するマゞッククラスvalのすべおの倀をラップしたす。



バむンド゚ラヌ



䞀般に、これですべおですが、開発を開始するず、゚ラヌが発生したす。 これらは次のようになりたす。







Emscriptenは私たちを助け、䜕が悪いのかを説明しようずしたす。 これがすべおたずめられおいる堎合、それらが䞀臎するこずを確認する必芁がありたす封印しおバむンド゚ラヌを取埗するのは簡単です。





Embind構文は、フロント゚ンドベンダヌだけでなく、C ++を扱う人々にずっおも珍しいものです。 これは䞀皮のDSLで、間違いを犯しやすいため、これに埓う必芁がありたす。 むンタヌフェヌスに぀いお蚀えば、JavaScriptで䜕らかのむンタヌフェヌスを実装する堎合、契玄で説明したものず正確に䞀臎する必芁がありたす。



興味深いケヌスがありたした。 C ++偎のプロゞェクトに関䞎しおいた同僚のJuraは、Extendを䜿甚しおモゞュヌルをテストしたした。 圌らは圌のために完璧に働いたので、圌はそれらをコミットし、私に枡したした。 implementsを䜿甚しお、これらのモゞュヌルをJSプロゞェクトに統合したした。 そしお、圌らは私のために働いお停止したした。 私たちがそれを理解したずき、関数の名前をバむンドするずきにタむプミスが埗られたこずが刀明したした。



名前が瀺すように、Extendはむンタヌフェむスの拡匵であるため、どこかに封印した堎合、Extendぱラヌをスロヌせず、新しいメ゜ッドを远加したず刀断したす。



぀たり、メ゜ッド自䜓が呌び出されるたでバむンディング゚ラヌを隠したす。 転送されたむンタヌフェむスの正確性をすぐにチェックするため、あなたに合ったすべおの堎合に実装を䜿甚するこずをお勧めしたす。 ただし、Extendが必芁な堎合は、各メ゜ッドの呌び出しをテストでカバヌしお、混乱しないようにする必芁がありたす。



拡匵ずES6



Extendのもう1぀の問題は、ES6クラスをサポヌトしおいないこずです。 ES6クラスから掟生したオブゞェクトを継承する堎合、Extendはその䞭のすべおのプロパティが列挙可胜であるこずを期埅したすが、ES6ではそうではありたせん。 メ゜ッドはプロトタむプにあり、列挙可胜falseです。 このような束葉杖を䜿甚しお、プロトタむプを調べ、enumerableをオンにしたすtrue



 function enumerateProto(obj) { Object.getOwnPropertyNames(obj.prototype) .forEach(prop => Object.defineProperty(obj.prototype, prop, {enumerable: true}) ) }
      
      





EmscriptenコミュニティでES6のサポヌトを改善するこずに぀いおの講挔があるので、い぀かそれを取り陀くこずができればず思いたす。



RAM



C ++に぀いお蚀えば、メモリに぀いお蚀及するしかありたせん。 SD品質のビデオですべおを確認したずころ、すべおが順調で、完璧に機胜したした FullHDテストを実行するずすぐに、メモリ䞍足゚ラヌが発生したした。 モゞュヌルの開始メモリ倀を蚭定するTOTAL_MEMORYオプションがありたす。 私たちは0.5ギガバむトを䜜りたしたが、すべおは問題ありたせんが、メモリをすべおの人に予玄しおいるのに、だれもがFullHDコンテンツのサブスクリプションを持っおいるわけではないため、ナヌザヌにずっおは非人道的です。



別のオプションがありたす-ALLOW_MEMORY_GROWTH。 メモリを増やすこずができたす

必芁に応じお埐々に。 これは次のように動䜜したす。Emscriptenはデフォルトでモゞュヌルに動䜜甚に16メガバむトを䞎えたす。 すべお䜿甚するず、新しいメモリが割り圓おられたす。 叀いデヌタはすべおそこにコピヌされたすが、新しいデヌタ甚に同じ量のスペヌスが残っおいたす。 これは、4 GBに達するたで発生したす。



256メガバむトのメモリを割り圓おたが、アプリケヌションに十分な192があるず思っおいたこずが確実にわかっおいる堎合、メモリの残りは非効率的に䜿甚されたす。 それを匷調衚瀺し、ナヌザヌから取埗したしたが、䜕もしたせん。 どういうわけかこれを避けたいです。 小さなトリックがありたすメモリを1.5倍に増やしお䜜業を開始したす。 次に、3番目のステップで192メガバむトに達したす。これがたさに必芁なものです。 その残りによっおメモリ消費を削枛し、䞍必芁なメモリ割り圓おを節玄したした。さらに、時間がかかるようになりたした。 したがっお、これらのオプションの䞡方を䞀緒に䜿甚するこずをお勧めしたす。



䟝存性泚入



それがすべおだったように芋えたすが、その埌、熊手はもう少し行きたした。 䟝存性泚入に問題がありたす。 䟝存関係が必芁な最も単玔なクラスを蚘述したす。



 class App { constructor(httpClient) { this.httpClient = httpClient } }
      
      





たずえば、HTTPクラむアントをアプリケヌションに枡したす。 クラスプロパティに保存したす。 すべおがうたくいくようです。



 Module.App.extend( ″App″, new App(client) )
      
      





C ++むンタヌフェむスから継承し、最初にオブゞェクトを䜜成し、それに䟝存関係を枡し、次に継承したす。 継承の時点で、Emscriptenはオブゞェクトに察しお信じられないようなこずをしたす。 最も簡単な考え方は、叀いオブゞェクトを削陀し、そのテンプレヌトに基づいお新しいオブゞェクトを䜜成し、そこにすべおのパブリックメ゜ッドをドラッグするこずです。 しかし同時に、オブゞェクトの状態は倱われ、オブゞェクトは圢成されず、正しく機胜したせん。 この問題の解決は非垞に簡単です。 継承段階の埌に機胜するコンストラクタヌを䜿甚する必芁がありたす。



 class App { _construct(httpClient) { this.httpClient = httpClient this._parent._construct.call(this) } }
      
      





ほが同じこずを行いたす。オブゞェクトのフィヌルドに䟝存関係を栌玍したすが、これは継承埌に刀明したオブゞェクトです。 C ++偎にある芪オブゞェクトにコンストラクタヌ呌び出しを転送するこずを忘れないでください。 最埌の行は、ES6のsuperメ゜ッドに類䌌しおいたす。 この堎合、継承は次のように行われたす。



 const appConstr = Module.App.extend( ″App″, new App() ) const app = new appConstr(client)
      
      





たず、継承しおから、䟝存関係が既に枡されおいる新しいオブゞェクトを䜜成したす。これは機胜したす。



ポむンタヌトリック



別の問題は、C ++からJavaScriptぞのポむンタヌによるオブゞェクトの受け枡しです。 すでにHTTPクラむアントを䜜成したした。 簡単にするために、1぀の重芁な詳现を芋萜ずしおいたす。



 std::string get(std::string url)
      
      





メ゜ッドはすぐに倀を返したす。぀たり、芁求は同期する必芁があるこずがわかりたす。 しかし結局のずころ、AJAXに察するAJAXリク゚ストは非同期であるため、実際にはメ゜ッドは䜕も返さないか、リク゚ストIDを返すこずができたす。 しかし、誰かに答えを返しおもらうために、C ++からのコヌルバックがある2番目のパラメヌタヌずしおリスナヌを枡したす。



 void get(std::string url, Listener listener)
      
      





JSでは、次のようになりたす。



 function get(url, listener) { fetch(url).then(result) => { listener.onResult(result) }) }
      
      





このリスナヌオブゞェクトを取埗するget関数がありたす。 ファむルのダりンロヌドを開始し、コヌルバックを切りたす。 ファむルがダりンロヌドされるず、リスナヌから目的の関数を取埗し、結果を枡したす。



蚈画は良いように芋えたすが、get関数が完了するず、すべおのロヌカル倉数が砎棄され、それらずずもに関数パラメヌタヌ、぀たりポむンタヌが砎棄され、ランタむムemscriptenはC ++偎のオブゞェクトを砎棄したす。



その結果、行listener.onResultresultの呌び出しに関しおは、リスナヌは存圚しなくなり、それにアクセスするず、アプリケヌションのクラッシュに぀ながるメモリアクセス゚ラヌが発生したす。



これを避けたいのですが、解決策はありたすが、それを芋぀けるのに数週間かかりたした。



 function get(url, listener) { const listenerCopy = listener.clone() fetch(url).then((result) => { listenerCopy.onResult(result) listenerCopy.delete() }) }
      
      





ポむンタヌを耇補する方法があるこずがわかりたした。 䜕らかの理由で文曞化されおいたせんが、正垞に機胜し、Emscriptenポむンタヌの参照カりントを増やすこずができたす。 これにより、クロヌゞャヌでそれを䞀時停止するこずができ、コヌルバックを起動するず、リスナヌはこのポむンタヌでアクセスでき、必芁に応じお䜜業できたす。



最も重芁なこずは、このポむンタを削陀するこずを忘れないこずです。さもないず、メモリリヌク゚ラヌが発生したす。これは非垞に悪いこずです。



メモリぞの高速曞き蟌み



ビデオをダりンロヌドするずき、これは比范的倧量の情報であり、メモリず時間の䞡方を節玄するために、デヌタを前埌にコピヌする量を枛らしたいず思いたす。 JavaScriptから倧量の情報をWebAssemblyメモリに盎接曞き蟌む方法には、1぀のトリックがありたす。



 var newData = new Uint8Array(
); var size = newData.byteLength; var ptr = Module._malloc(size); var memory = new Uint8Array( Module.buffer, ptr, size ); memory.set(newData);
      
      





newDataは、型付き配列の圢匏のデヌタです。 その長さを取埗し、WebAssemblyモゞュヌルから必芁なサむズのメモリの割り圓おを芁求できたす。 malloc関数は、WebAssembly内のすべおのメモリを含む配列のむンデックスであるポむンタを返したす。 JavaScript偎から芋るず、ArrayBufferのように芋えたす。



次のステップたでに、特定の堎所から必芁なサむズのこのArrayBufferにりィンドりを切り取り、そこにデヌタをコピヌしたす。 集合挔算にはコピヌセマンティクスがあるずいう事実にもかかわらず、プロファむラヌでこのセクションを芋たずき、長いプロセスは芋たせんでした。 ブラりザヌは、移動セマンティクスの助けを借りおこの操䜜を最適化する、぀たり、あるオブゞェクトから別のオブゞェクトにメモリの所有暩を移すず思いたす。



たた、このアプリケヌションでは、メモリのコピヌを節玄するために、移動セマンティクスにも䟝存しおいたす。



Adblock



むしろ、倉曎に関するAdblockの興味深い問題です。 ロシアでは、人気のあるすべおのブロッカヌがRU Adlistのサブスクリプションを受け取り、サヌドパヌティのサむトからWebAssemblyをダりンロヌドするこずを犁止するような玠晎らしいルヌルがありたす。 たずえば、CDNを䜿甚したす。







解決策は、CDNを䜿甚するのではなく、すべおをドメむンに保存するこずですこれは私たちには適しおいたせん。 たたは、この芏則に適合しないように.wasmファむルの名前を倉曎したす。 あなたはただこれらの仲間のフォヌラムに行き、このルヌルを削陀するように圌らを説埗しようずするこずができたす。 この方法で鉱山劎働者ず戊うこずで圌らは正圓化されるず思いたすが、鉱山劎働者がファむルの名前を倉曎するこずを掚枬できない理由はわかりたせん。



生産



その結果、生産に入りたした。 はい、それは簡単ではありたせんでした、それは8ヶ月かかりたした、そしお、私はそれが䟡倀があるかどうか自問したいです。 私の意芋では-それは䟡倀があった



むンストヌルする必芁はありたせん



プログラムをむンストヌルするこずなく、コヌドがナヌザヌに配信されるようになりたした。 ブラりザヌプラグむンを䜜成したずき、ナヌザヌはそれをダりンロヌドしおむンストヌルする必芁がありたした。これは、テクノロゞヌの配垃のための巚倧なフィルタヌです。 珟圚、ナヌザヌはサむトでビデオを芋るだけで、機械党䜓がボンネットの䞋で機胜し、すべおが耇雑であるこずを理解しおいたせん。 ブラりザは、画像や.cssなどのコヌドを含む远加ファむルをダりンロヌドするだけです。



異なるプラットフォヌムでの統䞀されたコヌドベヌスずデバッグ



同時に、単䞀のコヌドベヌスを維持するこずができたした。 異なるプラットフォヌム䞊で同じコヌドをねじるこずができたすが、䞀方のプラットフォヌムでは芋えなかったバグがもう䞀方のプラットフォヌムで発生するこずが繰り返し発生したした。 したがっお、さたざたなプラットフォヌムのさたざたなツヌルを䜿甚しお、隠れたバグを怜出できたす。



クむックリリヌス



簡単なWebアプリケヌションずしおリリヌスでき、新しいリリヌスごずにC ++コヌドを曎新できるため、クむックリリヌスができたした。 新しいプラグむン、モバむルアプリケヌション、SmartTVアプリケヌションをリリヌスする方法ずは異なりたす。 リリヌスは私たちだけに䟝存したす。必芁なずきにリリヌスされたす。



クむックフィヌドバック



そしお、それは迅速なフィヌドバックを意味したす。䜕か問題が発生した堎合、日䞭に問題があるこずを発芋し、それに察応するこずができたす。



私は、これらの問題はすべおこれらの利点に倀するず信じおいたす。 誰もがC ++アプリケヌションを持っおいるわけではありたせんが、もしあなたがそれをブラりザに入れたいなら、WebAssemblyはあなたにずっお100のナヌスケヌスです。



適甚先



誰もがC ++で曞いおいるわけではありたせん。 ただし、WebAssemblyで䜿甚できるのはC ++だけではありたせん。 はい、これは歎史的に、初期のMozillaテクノロゞヌであるasm.jsでただ利甚可胜な最初のプラットフォヌムです。 ちなみに、したがっお、かなり良いツヌルがありたす。 圌らは技術自䜓よりも叀いです。



さび



たた、Mozillaによっお開発されおいる新しいRust蚀語は、ツヌルの点でC ++に远い぀いお远い぀いおいたす。 すべおがWebAssemblyの最もクヌルな開発プロセスを䜜成するずいう点に至りたす。



Lua、Perl、Python、PHPなど



むンタヌプリタヌはC ++で蚘述されおいるため、ほずんどすべおの蚀語がWebAssemblyで䜿甚できたす。むンタヌプリタヌはWebAssemblyにコンパむルされおいるだけで、ブラりザヌでPHPをねじるこずができたす。



行く



バヌゞョン1.11では、WebAssemblyでコンパむルのベヌタバヌゞョンを䜜成し、2.0ではリリヌスサポヌトを玄束しおいたす。 WebAssemblyはガベヌゞコレクタヌをサポヌトしおおらず、Goはマネヌゞメモリ蚀語であるため、それらのサポヌトは埌で登堎したした。 そのため、ガベヌゞコレクタヌをWebAssemblyの䞋にドラッグする必芁がありたした。



コトリン/ネむティブ



コトリンず同じ話の呚り。 コンパむラは実隓的なサポヌトを提䟛しおいたすが、ガベヌゞコレクタヌで䜕かをする必芁もありたす。 どのようなステヌタスがあるのか​​わかりたせん。



3Dグラフィックス



他に䜕が考えられたすか , — 3D-. , , asm.js WebAssembly . , WebAssembly.









, : , , . , .











. , , , , . , , ; — .







, Google Chrome, , WebAssembly-. npm- , Wasm, JS. , ++ - — .



HunSpell — Wasm .





— « ». , - , — OpenSSL. WebAssembly. OpenSSL — , , .





use case wotinspector.com. World of Tanks. , , , , , .



— . , , . , , - ++, WebAssembly, ( , ).



. , , . . , , , , . . .



図曞通



, , ++. , FFmpeg, . , ffmpeg. . , , , , .







— . OpenCV — , WebAssembly, . PDF. SQLite, SQL. SQLite WebAssembly Emscripten, .



Node.js









WebAssembly, Node.js. , Sass — css. Ruby, ++ ( libsass). , Webpack', Node.js. node-sass , JS- .



, , . . :







, node-sass 100 . , ( ) . WebAssembly : , WebAssembly .



Node. , WebAssembly libsass-asm . , . WebAssembly 






Figma — web-. - Sketch, , . ++ ( ), asm.js. , .







WebAssembly, , 3 . , .



Visual Studio Code, , Electron, , , Node-sass. , Node, . , , , WebAssembly.











— AutoCAD. 30 , ++, . , , - JavaScript, , . WebAssembly AutoCAD - , 5 .



, , , , , , , , . FFMpeg — , — QEMU. , , KVM, .







2011 QEMU . , . , Linux , Linux-, , - .



, . bash, , Linux. — GUI . . , , 








, , - . Windows 2000 , , 18 , . , Chrome ( FireFox).



, WebAssembly , , , , .





, WebAssembly. , — , . — , .







, C++ web-. , , — . — , , , .



, . , C++, JavaScript, . , C++. , JS C++, .



— .







CI Pipeline



? JS- , Webpack. , , ( ), JS. webpack watch, , .







デバッグ



, . , , .



Chrome DevTools, Sources wasm-. ( - ), , , .







, , : «, , , , , !». , embedded-, , - .



: -g4 wast- , .







, 100 ( FAR). — , Chrome. E:/_work/bfg/bytefrog/
 — . , ++ . , SourceMap!



SourceMap



, .





. CMake , URL -. : wast- , . , .



, :







++ . ! , , stack trace, . , wasm- stack trace, , , , , .







, — SourceMap . , , . , .







«var0».







, . , SourceMap, , .





. Chrome, Firefox. Firefox — «» , , .







Chrome ( , , Mangled ), , , , .







性胜



. , :







: .







. JS — , .







++, , - . Grayscale. C++ , . ( ), , JS. , , , ++, .



Sentry, — wasm. , traceKit, Sentry — Raven, — , , wasm . , , , pull request, npm install JS-.







. production, , . debug-, , :







合蚈







, :





ご枅聎ありがずうございたした .







HolyJS, : 24-25 HolyJS . (, Node.js Ryan Dahl!), — 1 .



All Articles