postMessageはとても役に立ちます

15821 ワード

前言:この文章は皆さんと一緒にpostMessageをよく認識して、その互換性、対応するAPIの紹介、およびよくあるいくつかの使用シーンを含めて、同じ困惑している盆友たちに少し啓発して、この技術を使う必要がある同僚たちに少し助けてほしいです.
postMessageの定義
postMessageはhtml 5に導入するAPIであり、postMessage()方法は異なるソースからのスクリプトが非同期方式で有効な通信を行うことを可能にし、文書ドキュメント、マルチウィンドウ、ドメイン間メッセージ伝達を実現することができる.ウィンドウ間のデータ通信に用いることが多く、ドメイン間通信の有効な解決策となる.
PostMessageの互換性
下図はcaniuseで検索postMessage互換性の断面図であり、IEブラウザのサポート度が比較的低いことを除き、他のブラウザのサポート度は良好である.
postMessage APIの紹介
送信データ:
otherWindow.postMessage(message, targetOrigin, [transfer]);

otherWindow
ウィンドウの1つの引用、例えばiframeのcontentWindow属性、windowを実行します.Openが返すウィンドウオブジェクト、または名前付きまたは数値インデックスのwindow.frames.
message
他のウィンドウに送信するデータは、[!構造化されたクローンアルゴリズム](Structural Clone Algorithm)(https://developer.mozilla.org/en-US/docs/DOM/The_structured_clone_algorithm)シーケンス化これは、自分でシーケンス化することなく、データオブジェクトをターゲットウィンドウに安全に転送できることを意味する.
targetOrigin
ウィンドウのorigin属性によりメッセージイベントを受信できるウィンドウを指定し、指定後はoriginの下のウィンドウに対応するのみメッセージを受信することができ、ワイルドカード「*」に設定すると任意のウィンドウに送信できることを示すが、通常はセキュリティ上の考慮では推奨されない.現在のウィンドウと同じソースのウィンドウに送信する場合は、[/]に設定します.
Transfer|オプション属性
メッセージと同時に送信*Transferable**オブジェクトの一連であり、これらのオブジェクトの所有権はメッセージの受信者に転送され、送信側は所有権を保有しない.
受信データ:messageイベントの発生を傍受する
window.addEventListener("message", receiveMessage, false) ;
function receiveMessage(event) {
     var origin= event.origin;
     console.log(event);
}

eventオブジェクトの印刷結果の断面図は次のとおりです.
ここではeventオブジェクトの4つのプロパティに重点を置きます
  • data:他のウィンドウから送信されたメッセージオブジェクトを指す.
  • type:メッセージを送信するタイプを指す.
  • source:メッセージを送信するウィンドウオブジェクトを指す.
  • origin:メッセージを送信するウィンドウのソース
  • を指す.
    postMessageの使用シーン
    シーン1ドメイン間通信(GETリクエストとPOSTリクエストを含む)
    JSONPはGET要求のドメイン間問題を解決することができることはよく知られているが、POST要求のドメイン間問題を解決することはできない.postMessageでもいいですここではただ一つの例を挙げますが、参考までに、具体的なコードをどのように書くかは具体的なシーンで決めます.
    親フォームはドメイン間iframeを作成し、情報を送信します.
    
    
        
            "utf-8">
            "X-UA-Compatible" content="IE=edge">
              POST    
            type</span>=<span class="hljs-string">"text/JavaScript"</span>>    
                // sendPost   postMessage               moweide.gitcafe.io ,
                //             
                <span class="hljs-keyword">function</span> <span class="hljs-function"><span class="hljs-title">sendPost</span></span>() {        
                    //   id otherPage iframe            
                    var iframeW<span class="hljs-keyword">in</span> = document.getElementById(<span class="hljs-string">"otherPage"</span>).contentWindow;        
                    //                 
                    iframeWin.postMessage(document.getElementById(<span class="hljs-string">"message"</span>).value, 
                        <span class="hljs-string">'http://moweide.gitcafe.io'</span>);    
                }    
                //              
                window.addEventListener(<span class="hljs-string">"message"</span>, <span class="hljs-keyword">function</span>(event) {        
                    console.log(event, event.data);    
                }, <span class="hljs-literal">false</span>);
            
        
         
             
            type="button" value="  " onclick="sendPost()"> 
            
        
    
    

    サブフォームは情報を受信して処理します
    
    
        
            "utf-8">
            "X-UA-Compatible" content="IE=edge">
            POST Handler
            "//code.jquery.com/jquery-1.11.0.min.js"</span>>
            type</span>=<span class="hljs-string">"text/JavaScript"</span>>
                window.addEventListener(<span class="hljs-string">"message"</span>, <span class="hljs-keyword">function</span>( event ) {
                    //                   post  
                    var data = event.data;
                    $.ajax({
                        //      url      .                       
                        <span class="hljs-built_in">type</span>: <span class="hljs-string">'POST'</span>, 
                        url: <span class="hljs-string">'http://moweide.gitcafe.io/getData'</span>,
                        data: <span class="hljs-string">"info="</span> + data,
                        dataType: <span class="hljs-string">"json"</span>
                    }).done(<span class="hljs-keyword">function</span>(res){        
                        //            postMessage              
                        window.parent.postMessage(res, <span class="hljs-string">"*"</span>);    
                    }).fail(<span class="hljs-keyword">function</span>(res){        
                        //            postMessage              
                        window.parent.postMessage(res, <span class="hljs-string">"*"</span>);    
                    });
                }, <span class="hljs-literal">false</span>);
            
        
    
        
    

    シーン2 WebWorker
    JavaScript言語は単一スレッドモデルを採用しており、通常、すべてのタスクは1つのスレッドで完了し、一度に1つのことしかできない.後のタスクは前のタスクが実行されてから実行を開始することができるが、この方法は複雑な時間の計算に遭遇すると、ブロックが発生し、アプリケーションの正常な実行を深刻に阻害する.Web Workerは、Webコンテンツがバックグラウンドスレッドでスクリプトを実行するための簡単な方法を提供し、スレッドはユーザーインタフェースに干渉することなくタスクを実行することができる.作成すると、workerは、その作成するJavaScriptコードにメッセージを送信し、メッセージを変更コードで指定されたイベントハンドラにパブリッシュすることができる.
    1つのwokerは、1つのコンストラクション関数を使用してオブジェクトを作成し、名前付きJavaScriptファイルを実行する-このファイルはワークスレッドで実行するコードを含み、wokerは別のグローバルコンテキストで実行され、現在のwindowとは異なり、windowを使用して全局属性を取得することはできません.
    いくつかの限界
  • は同源スクリプトファイルのみをロードすることができ、DOMノード
  • を直接操作することはできない.
  • Workerスレッドではalert()メソッドとconfirm()メソッドは実行できませんが、XMLHttpRequestオブジェクトを使用してAJAXリクエスト
  • を発行できます.
  • ローカルファイルを読み取ることができず、ネットワークファイル
  • のみをロードすることができる.
  • もwindowオブジェクトのデフォルトの方法と属性を使用することはできませんが、webSocket、indexedDB、FireFoxOS専用のDアタスストアAPIなどのデータ格納メカニズムを含む多くのwindowオブジェクトの下のものを使用することができます.詳細については、Functions and classes available to workersを参照してください.

  • workersとプライマリ・スレッド間のデータ転送は、postMessage()メソッドを使用してそれぞれのメッセージを送信し、onmessageイベント処理関数を使用してメッセージに応答する(メッセージはMessageイベントのdata属性に含まれる).この過程でデータは共有されるのではなく複製される.wokerは専用workerと共有workerに分けられ、1つの専用workerが初めて生成するスクリプトで緊急に使用され、共有wokerは同時に複数のスクリプトで使用することができる.
    専用wokerの使用例:
    // main.js
    if(window.Worker) {
        var myWorker = new Worker('http://xxx.com/worker.js');
        //     
        first.onchange = function() {
            myWorker.postMessage([first.value, second.value]);
            console.log("Message posted to worker");
        }
        second.onchange = function() {
          myWorker.postMessage([first.value,second.value]);
          console.log('Message posted to worker');
        }
        //       onmessage   worker     
        myWorker.onmessage = function (e) {
          var textContent = e.data;
          console.log("message received from worker");  
        }
    }
    
    // worker.js
    
    //   selfduixiang,,       , worker         ,   importScripts()  
    onmessage = function(e) {
        console.log("message received from main script");
        var workerResult = "Result: " + (e.data[0] * e.data[1]);
        console.log("posting message\back to main script");
        postMessage(workerResult);
    }

    Web Workerの使用シーンは、埋込データを収集するためのものであり、大量の複雑なデータ計算、複雑な画像処理、ビッグデータの処理に用いることができる.メインスレッドの正常な実行とページUIのレンダリングを阻害しないためである.
    埋点データ収集下での使用:main.jsで収集するデータは、収集した情報をpostMessageでworkerに送信する.js、woker.jsでは関連演算と整理を行い、サーバ側に送信する.もちろん、Web Wokerを用いることなく、単一ページアプリケーションにおけるindexを通過する.htmlの中でiframeを作成してもページ間の切り替えを実現することができて、ページの滞在時間の長さなどのデータの採集、具体的な実現は私は詳しく話しません、興味のある学生はネット上で解決策を検索することができて、どんな疑問が私信を歓迎します~~~
    シーン3 Service Worker
    サービスWorkerの存在はブラウザコンソールのアプリケーションで確認できます
    Service Workerは、Webアプリケーションがオフラインで格納される最適なソリューションです.Service WorkerとWeb Workerの同じ点は、従来のjsエンジンスレッド以外に、プライマリ・スレッドで処理するのに適さないビジネスを処理する新しいjsスレッドを開発することです.異なる点は、主に以下の点です.
  • Web Workerは特定のページにサービスするが、サービスWorkerは登録インストール後に複数のページで
  • を使用することができる.
  • Service Workerはブラウザに常駐する、ページのクローズによって破棄されることはない.本質的には、バックグラウンドスレッドであり、アクティブに終了したり、ブラウザが回収したりしてこそ、このスレッドは終了します.
  • ライフサイクル、呼び出し可能なAPIも異なる
  • ServiceWorkerを使用してキャッシュを行い、jsを使用してブラウザのhttpリクエストをブロックし、キャッシュファイルを設定してオフラインウェブアプリケーションを作成することができます.サービスWorkerの概念についての紹介はここまでです~~、興味のある方は関連記事を探して勉強して、疑問のある方は私信を歓迎して私と検討してください~,ここで主にpostMessageの方法を使ってサービスWorkerとページ間の通信を行うことを紹介します.
    ページからサービスWorkerへのメッセージの送信
    注意する必要があるのは、このページがブラウザに直接投げ込まれた場合(fileプロトコルを使用している)、開くのは間違っています.nginxを使用してポートマッピングを行うか、nodeを使用してサーバーを構築して(httpプロトコルを使用して)このページにアクセスします(現在、閲覧器がfileプロトコルが開いているファイルにいくつかのサービスの制限をしているためだと推測しています.ポートマッピングのための私のnginxの構成も添付します.
    
    
    
    "utf-8">
    "X-UA-Compatible" content="IE=edge">
    Service Worker     
    
    
        
        "sw1.js"</span>> 
        "sw2.js"</span>> 
        type</span>=<span class="hljs-string">"text/JavaScript"</span>>
            <span class="hljs-keyword">if</span>(<span class="hljs-string">'serviceWorker'</span> <span class="hljs-keyword">in</span> window.navigator) {
                //       scope   Service Worker,         Service Worker    
                navigator.serviceWorker.register(<span class="hljs-string">'./sw1.js'</span>, { scope:<span class="hljs-string">'./sw1'</span>})
                    .then(<span class="hljs-keyword">function</span>(reg) {
                        console.log(<span class="hljs-string">'success'</span>, reg);
                        <span class="hljs-built_in">return</span> new Promise((resolve, reject) => {
                            const interval = <span class="hljs-built_in">set</span>Interval(<span class="hljs-function"><span class="hljs-title">function</span></span>() {
                                <span class="hljs-keyword">if</span>(reg.active) {
                                    clearInterval(interval);
                                    resolve(reg.active);
                                }    
                            }, 1000);
                        }).then(sw => {
                            sw.postMessage(<span class="hljs-string">"this message is from page to sw1"</span>);
                        })
                        
                    })
                navigator.serviceWorker.register(<span class="hljs-string">'./sw2.js'</span>, { scope:<span class="hljs-string">'./sw2'</span>})
                    .then(<span class="hljs-keyword">function</span>(reg) {
                        console.log(<span class="hljs-string">'success'</span>, reg);
                        <span class="hljs-built_in">return</span> new Promise((resolve, reject) => {
                            const interval = <span class="hljs-built_in">set</span>Interval(<span class="hljs-function"><span class="hljs-title">function</span></span>() {
                                <span class="hljs-keyword">if</span>(reg.active) {
                                    clearInterval(interval);
                                    resolve(reg.active);
                                }    
                            }, 1000);
                        }).then(sw => {
                            sw.postMessage(<span class="hljs-string">"this message is from page to sw2"</span>);
    
                        })
                        
                    });
                    navigator.serviceWorker.addEventListener(<span class="hljs-string">'message'</span>, <span class="hljs-keyword">function</span> (event) {
                        console.log(event.data);
                        //     ,     DOM  
                        document.getElementById(<span class="hljs-string">'showArea'</span>).value = event.data ;
                    });
            }
        
        
    
    
    
    // sw1.js
    self.addEventListener("message", function(event) {
        console.log("sw1.js " + event.data);
        event.source.postMessage('this message is from sw1.js, to page');
    });
    
    // sw2.js
    
    self.addEventListener("message", function(event) {    
        console.log("sw2.js " + event.data); 
         // event.source               
        event.source.postMessage('this message is from sw2.js, to page');
    });

    nginxはポートマッピングに関する構成を行います.
    // nginx.conf
    //           nginx       
    //     nginx       conf.d             .
    //            include  
    
     http {    
        #               nginx         
        include conf.d/*.conf; 
    }
    
    
    // testHtml.conf
    server {    
        listen 9090;    
        server_name       localhost;
        location / {        
            root  C:/Users/hzljie/Desktop/test/testb;  
            #              ,                         
            index  test.html test.htm;    
        }
    }
    
    
    

    実行された効果のスクリーンショット:
    これでサービスWorkerと他のページとの通信が実現し、興味のある仲間が一緒にやってみることができます.もしあなたが間違ったことを報告したら、自分のコードをよくチェックしてください.
    締めくくり
    ええと、一苦労してやっとまとめましたが、文章は详しくないかもしれません.结局、一つの技术には多くの拡张と分岐分野があります.一つ一つ绍介するのは难しいです.私のブログを书くレベルも向上しなければなりません.研究や兴味があるか、文章に间违いがあることを発见した友达と私の交流を歓迎します.メールアドレス[email protected].
    以前の文章.
    vueでSockJSを用いてwebSocket通信を実現
    表の表の頭を浮かべるように手を教えてあげます(table-header-fixed)
    Expires,Last-Modified,Etagキャッシュメカニズム
    転載先:https://juejin.im/post/5b8359f351882542ba1dcc31