HTML5之postMessage 和onmessage讲解

2024-06-22 16:58

本文主要是介绍HTML5之postMessage 和onmessage讲解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1 H5 postMessage 和 onmessage
    • 1.1 引言
    • 1.2 Web Workers
      • 1.2.1 Web Workers简介
      • 1.2.2 在Web Workers中使用 postMessage 和 onmessage
    • 1.3 Cross-document messaging
      • 1.3.1 Cross-document messaging 简介
      • 1.3.2 在Cross-document messaging中使用 postMessage 和 onmessage
    • 1.4 WebSockets
      • 1.4.1 WebSockets 简介
      • 1.4.2 在WebSockets中使用 send 和 onmessage
    • 1.5 Server-Sent Events
      • 1.5.1 Server-Sent Events 简介
      • 1.5.2 在 Server-Sent Events 中使用 onmessage

1 H5 postMessage 和 onmessage

1.1 引言

随着 HTML5 的发展,了解并熟悉 HTML5API 接口是非常重要的。postMessage(send) 和 onmessage 此组 APIHTML5 中有着广泛的应用,比如 Web Workers 中应用此组 API 实现多个线程间 JavaScript 调用功能 ,Cross-document messaging 中实现两个不同域间 JavaScript 调用功能等等。本文主要介绍此组 APIWeb WorkersCross-document messagingWebSockets 以及 Server-Sent Events 中的详细应用情况。

1.2 Web Workers

1.2.1 Web Workers简介

至 2008 年 W3C 制定出第一个 HTML5 草案开始,HTML5 承载了越来越多崭新的特性和功能。它不但强化了 Web 系统或网页的表现性能,而且还增加了对本地数据库等 Web 应用功能的支持。其中,最重要的一个便是对多线程的支持。在 HTML5 中提出了工作线程(Web Workers)的概念,并且规范出 Web Workers 的三大主要特征:能够长时间运行(响应),理想的启动性能以及理想的内存消耗。Web Workers 允许开发人员编写能够长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的及时响应。
Web WorkersWeb 前端网页上的脚本提供了一种能在后台进程中运行的方法。一旦它被创建,Web Workers 就可以通过 postMessage 向任务池发送任务请求,执行完之后再通过 postMessage 返回消息给创建者指定的事件处理程序 ( 通过 onmessage 进行捕获 )。Web Workers 进程能够在不影响用户界面的情况下处理任务,并且,它还可以使用 XMLHttpRequest来处理I/O,但通常,后台进程(包括 Web Workers 进程)不能对 DOM进行操作。如果希望后台程序处理的结果能够改变 DOM,只能通过返回消息给创建者的回调函数进行处理。
浏览器对 HTML5支持情况可以参考网站 https://caniuse.com/

1.2.2 在Web Workers中使用 postMessage 和 onmessage

首先,需要在客户端页面的 JavaScript 代码中 new 一个 Worker 实例出来,参数是需要在另一个线程中运行的 JavaScript文件名称。然后在这个实例上监听 onmessage 事件。最后另一个线程中的 JavaScript 就可以通过调用 postMessage方法在这两个线程间传递数据了

主线程中创建 Worker 实例,并监听 onmessage 事件

 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Test Web worker</title> <script type="text/JavaScript"> function init(){ var worker = new Worker('compute.js'); //event参数中有data属性,就是子线程中返回的结果数据worker.onmessage= function (event) { // 把子线程返回的结果添加到 div 上document.getElementById("result").innerHTML += event.data+"<br/>"; }; } </script> </head> <body onload="init()"> <div id="result"></div> </body> </html>

在客户端的 compute.js 中,只是简单的重复多次加和操作,最后通过 postMessage 方法把结果返回给主线程,目的就是等待一段时间。而在这段时间内,主线程不应该被阻塞,用户可以通过拖拽浏览器,变大缩小浏览器窗口等操作测试这一现象。这个非阻塞主线程的结果就是 Web Workers 想达到的目的。

compute.js 中调用 postMessage 方法返回计算结果

var i=0; function timedCount(){ for(var j=0,sum=0;j<100;j++){ for(var i=0;i<100000000;i++){ sum+=i; } } // 调用 postMessage 向主线程发送消息postMessage(sum); } postMessage("Before computing,"+new Date()); timedCount(); postMessage("After computing,"+new Date());

1.3 Cross-document messaging

1.3.1 Cross-document messaging 简介

由于同源策略的限制,JavaScript 跨域的问题,一直是一个颇为棘手的问题。HTML5 提供了在网页文档之间互相接收与发送信息的功能。使用这个功能,只要获取到网页所在窗口对象的实例,不仅同源(域 + 端口号)的 Web 网页之间可以互相通信,甚至可以实现跨域通信。 要想接收从其他窗口发送来的信息,必须对窗口对象的 onmessage 事件进行监听,其它窗口可以通过 postMessage 方法来传递数据。该方法使用两个参数:第一个参数为所发送的消息文本,但也可以是任何 JavaScript 对象(通过 JSON 转换对象为文本),第二个参数为接收消息的对象窗口的 URL 地址,可以在 URL 地址字符串中使用通配符*指定全部地。

1.3.2 在Cross-document messaging中使用 postMessage 和 onmessage

为了实现不同域之间的通信,需要在操作系统的 hosts 文件添加两个域名,进行模拟。

hosts 文件中添加两个不同的域名

 127.0.0.1     parent.com 127.0.0.1       child.com

在父网页中通过 iframe 嵌入子页面,并在 JavaScript代码中调用 postMessage 方法发送数据到子窗口。

父页面中嵌入子页面,调用 postMessage 方法发送数据

 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Test Cross-domain communication using HTML5</title> <script type="text/JavaScript"> function sendIt(){ // 通过 postMessage 向子窗口发送数据document.getElementById("otherPage").contentWindow .postMessage( document.getElementById("message").value, "http://child.com:8080"); } </script> </head> <body> <!-- 通过 iframe 嵌入子页面 --> <iframe src="http://child.com:8080/TestHTML5/other-domain.html" id="otherPage"></iframe> <br/><br/> <input type="text" id="message"><input type="button" value="Send to child.com" onclick="sendIt()" /> </body> </html>

在子窗口中监听 onmessage 事件,并用 JavaScript 实现显示父窗口发送过来的数据。

子窗口中监听 onmessage 事件,显示父窗口发送来的数据

 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Web page from child.com</title> <script type="text/JavaScript"> //event 参数中有 data 属性,就是父窗口发送过来的数据window.addEventListener("message", function( event ) { // 把父窗口发送过来的数据显示在子窗口中document.getElementById("content").innerHTML+=event.data+"<br/>"; }, false ); </script> </head> <body> Web page from http://child.com:8080 <div id="content"></div> </body> </html>

父窗口嵌入子窗口
在这里插入图片描述

父窗口发送数据到子窗口
在这里插入图片描述

1.4 WebSockets

1.4.1 WebSockets 简介

Web 应用中,HTTP 协议决定了客户端和服务端连接是短连接,即客户端 Request,服务端 Response,连接断开。要想实现客户端和服务端实时通信,只能通过客户端轮询来实现。服务端推送数据也并不是字面上意思上的直接推,其实还是客户端自己取。WebSocketsHTML5 规范新引入的功能,用于解决浏览器与后台服务器双向通讯的问题,使用 WebSockets 技术,后台可以随时向前端推送消息,以保证前后台状态统一。

1.4.2 在WebSockets中使用 send 和 onmessage

由于主要介绍 postMessage(send)onmessage 客户端 API 的应用,而 WebSockets 涉及到服务器端代码的实现,所以本文将选取最简单的服务器端框架来编写服务器代码。WebSockets 服务器端有 jetty 提供的基于 Java 的实现,有 WebSocket-Node 基于 node.js 的实现,在 .Net 4.5 中也直接提供了 WebSockets 的支持。本文将使用 WebSocket-Node 提供的示例代码,稍作修改作为 WebSockets 的服务器端

首先,需要在客户端通过 JavaScript 代码 new 一个 WebSocket 实例出来,参数是实现 WebSocket 服务器端 URL 地址。然后在这个实例上监听 onmessage 事件接收服务器端发送过来的数据。当然,客户端也可以调用 send方法,发送数据到服务器端。

创建 WebSocket 对象,并监听 onmessage 事件

 connect : function() { var location ="ws://localhost:8000/"; // 创建 WebSockets 并传入 WebSockets server 地址this._ws =new WebSocket(location); this._ws.onmessage=this._onmessage; //WebSockets 还提供了 onopen 以及 onclose 事件this._ws.onopen =this._onopen; this._ws.onclose =this._onclose; }

_onmessage 方法中,接收数据,并显示在页面上

_onmessage 方法

 _onmessage : function(event) { //event 参数中有 data 属性,就是服务器发送过来的数据if (event.data) { var messageBox = document.getElementById('messageBox'); var spanText = document.createElement('span'); spanText.className ='text'; // 把服务器发送过来的数据显示在窗口中spanText.innerHTML = event.data; var lineBreak = document.createElement('br'); messageBox.appendChild(spanText); messageBox.appendChild(lineBreak); messageBox.scrollTop = messageBox.scrollHeight - messageBox.clientHeight; } },

_onopen方法中,调用 _send 方法发送一条消息到服务器端,告之连接已经建立。在_onclose 方法中,把 WebSocket 的实例设置成 null,释放资源。

_onopen,_onclose 以及 send 方法

 _onopen : function() { server._send("Client:Open WebSockets,"+new Date()); }, //message 参数就是客户端向服务器端发送的数据_send : function(message) { if (this._ws) this._ws.send(message); }, // 此方法提供外部代码调用send : function(text) { if (text !=null&& text.length >0) server._send(text); }, _onclose : function(m) { this._ws =null; }

把这些方法封装在一个 server对象中,方便提供外部调用。用户只需要先调用 serverconnect方法建立连接,然后调用 send 方法发送数据。

封装客户端实现

 var server = { // 对外主要提供 connect 和 send 方法connect : function() {...}, _onopen : function() {...}, _send : function(message) {...}, send : function(text) {...}, _onmessage : function(event) {...}, _onclose : function(m) {...} };

在服务器端,通过 JavaScript 语言简单修改 WebSocket-Node 中提供的 echo-server.js 示例即可

WebSockets 服务器端简单实现

 // 监听客户端的连接请求wsServer.on('connect', function(connection) { function sendCallback(err) { if (err) console.error("send() error: " + err); } // 监听客户端发送数据的请求connection.on('message', function(message) { if (message.type === 'utf8') {// 区别客户端发过来的数据是文本还是二进制类型connection.sendUTF( "Server:Get message:<br/>"+message.utf8Data, sendCallback ); } else if (message.type === 'binary') { connection.sendBytes(message.binaryData, sendCallback); } }); connection.on('close', function(reasonCode, description) { }); });

1.5 Server-Sent Events

1.5.1 Server-Sent Events 简介

HTML5 Server-Sent 事件模型允许您从服务器 push 实时数据到浏览器。利用 Eventsource 对象处理与页面间的接收和发送数据。在客户端,我们使用 HTML5+JavaScript,服务端使用 Java。在现存的 Ajax 模式中,web 页面会持续不断地请求服务器传输新数据,由客户端负责请求数据。而在服务端发送模式下,无需在客户端代码中执行连续的数据请求,而是由服务端 push推送更新。一旦在页面中初始化了 Server-Sent 事件,服务端脚本将持续地发送更新。客户端 JavaScript代码一旦接收到更新就将新的数据写入页面中展示出来。

1.5.2 在 Server-Sent Events 中使用 onmessage

Server-Sent EventsWebSockets 有相同之处,WebSockets 实现了服务器端以及客户端的双向通信功能,而 Server-Sent Events 则仅是指服务器端到客户端的单向通信,而且 Server-Sent Events 同样需要服务器端的实现,本文将使用基于 JavaServlet 技术实现服务器端
首先,在客户端通过 JavaScript 代码 new 一个 EventSource实例出来,参数是实现 EventSource 服务器端URL 地址。然后在这个实例上监听 onmessage事件接收服务器端发送过来的数据。

创建 EventSource 对象,并监听 onmessage 事件

 if (!!window.EventSource) { // 创建 EventSource 实例,传入 server 地址var source = new EventSource('/TestHTML5/ServerSentEvent'); } else { console.log("Your browser doesn't support server-sent event"); } // 监听 message 事件,等待接收服务器端发送过来的数据source.addEventListener('message', function(event) { //event 参数中有 data 属性,就是服务器发送过来的数据console.log(event.data); }, false); //EventSource 还提供了 onopen 以及 onerror 事件source.addEventListener('open', function(event) { }, false); source.addEventListener('error', function(event) { if (event.readyState == EventSource.CLOSED) { } }, false);

服务器端,在 Java 语言实现的 Servlet doGet 方法中使用 response 对象向客户端写数据

服务器端简单实现

 // 这里必须设置 Content-Type 为 text/event-stream response.setHeader("Content-Type", "text/event-stream"); response.setHeader("Cache-Control", "no-cache"); response.setCharacterEncoding ("UTF-8"); String id = new Date().toString(); response.getWriter().println("id:"+id); // 向客户端写两行数据response.getWriter().println("data:server-sent event is working."); response.getWriter().println("data:test server-sent event multi-line data"); response.getWriter().println(); response.getWriter().flush();

点击了解JavaScript中postMessage

这篇关于HTML5之postMessage 和onmessage讲解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1084879

相关文章

vite搭建vue3项目的搭建步骤

《vite搭建vue3项目的搭建步骤》本文主要介绍了vite搭建vue3项目的搭建步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1.确保Nodejs环境2.使用vite-cli工具3.进入项目安装依赖1.确保Nodejs环境

Nginx搭建前端本地预览环境的完整步骤教学

《Nginx搭建前端本地预览环境的完整步骤教学》这篇文章主要为大家详细介绍了Nginx搭建前端本地预览环境的完整步骤教学,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录项目目录结构核心配置文件:nginx.conf脚本化操作:nginx.shnpm 脚本集成总结:对前端的意义很多

前端缓存策略的自解方案全解析

《前端缓存策略的自解方案全解析》缓存从来都是前端的一个痛点,很多前端搞不清楚缓存到底是何物,:本文主要介绍前端缓存的自解方案,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、为什么“清缓存”成了技术圈的梗二、先给缓存“把个脉”:浏览器到底缓存了谁?三、设计思路:把“发版”做成“自愈”四、代码

通过React实现页面的无限滚动效果

《通过React实现页面的无限滚动效果》今天我们来聊聊无限滚动这个现代Web开发中不可或缺的技术,无论你是刷微博、逛知乎还是看脚本,无限滚动都已经渗透到我们日常的浏览体验中,那么,如何优雅地实现它呢?... 目录1. 早期的解决方案2. 交叉观察者:IntersectionObserver2.1 Inter

Vue3视频播放组件 vue3-video-play使用方式

《Vue3视频播放组件vue3-video-play使用方式》vue3-video-play是Vue3的视频播放组件,基于原生video标签开发,支持MP4和HLS流,提供全局/局部引入方式,可监听... 目录一、安装二、全局引入三、局部引入四、基本使用五、事件监听六、播放 HLS 流七、更多功能总结在 v

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

vue监听属性watch的用法及使用场景详解

《vue监听属性watch的用法及使用场景详解》watch是vue中常用的监听器,它主要用于侦听数据的变化,在数据发生变化的时候执行一些操作,:本文主要介绍vue监听属性watch的用法及使用场景... 目录1. 监听属性 watch2. 常规用法3. 监听对象和route变化4. 使用场景附Watch 的

前端导出Excel文件出现乱码或文件损坏问题的解决办法

《前端导出Excel文件出现乱码或文件损坏问题的解决办法》在现代网页应用程序中,前端有时需要与后端进行数据交互,包括下载文件,:本文主要介绍前端导出Excel文件出现乱码或文件损坏问题的解决办法,... 目录1. 检查后端返回的数据格式2. 前端正确处理二进制数据方案 1:直接下载(推荐)方案 2:手动构造

Vue实现路由守卫的示例代码

《Vue实现路由守卫的示例代码》Vue路由守卫是控制页面导航的钩子函数,主要用于鉴权、数据预加载等场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、概念二、类型三、实战一、概念路由守卫(Navigation Guards)本质上就是 在路

uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)

《uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)》在uni-app开发中,文件上传和图片处理是很常见的需求,但也经常会遇到各种问题,下面:本文主要介绍uni-app小程序项目中实... 目录方式一:使用<canvas>实现图片压缩(推荐,兼容性好)示例代码(小程序平台):方式二:使用uni