最近使用 iframe 的时候想要获取 iframe 文档信息的时候遇到了跨域问题,最后使用 postmessage 做父子页面通信解决需求也顺便学习了下 webworker 的使用 webWoker 使用依赖 postMessage() 和 onMessage(), 所以先说这两个吧
postMessage && onMessage
提供网页文档之间互相发送和接收信息的功能,可用于解决跨域访问的问题
会在所有页面脚本执行完毕之后(包括方法之后或者之前设置的 timeout 事件)再执行
挂载于 window 对象上
postMessage 语法: otherWindow.postMessage(message, targetOrigin, [transfer]); message: 发送的数据,不限类型,因为他自己会序列化 targetOrigin:通过窗口的 origin 属性指定哪些窗口能接收到消息事件,其值可以是字符串”*“(表示无限制)或者一个 URI transfer:可选参数;一个 Transferable 对象([什么是 Transferable[(https://developer.mozilla.org/zh-CN/docs/Web/API/Transferable)),和message 同时传递的,对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权
onMessage 语法 1 2 window .addEventListener('message' , function (event ) { ... })window .onmessage = function (event ) { ... }
获取到的 event 对象包含 data:接收的数据对象,对应 postMessage 的 message 参数 origin:消息发送方窗口的 origin,字符串由 协议、“://“、域名、“ : 端口号”拼接而成 source:对发送消息的窗口对象的引用
举个小栗子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // 在 iframe 加载完毕后,获取 iframe 的 window 对象,调用 postMessage 方法 <body > <div > a page</div > <iframe src ="b.html" id ="frame" > </iframe > <script > var frame = document .getElementById('frame' ); frame.onload = function ( ) { frame.contentWindow.postMessage({ name : 'a page' }, '*' ); }; </script > </body > // 子页面监听 message 事件设置回调打印 event <body > <div > b page</div > <script > window .addEventListener( 'message' , (event ) => console .log('this b page' , event), false ); </script > </body >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // 父页面监听 message 事件设置回调打印 event <body > <div > a page</div > <iframe src ="b.html" id ="frame" > </iframe > <script > window .addEventListener( 'message' , (event ) => console .log('this a page' , event), false ); </script > </body > // 使用 parent 获取 window 对象,调用 postMessage 方法 <body > <div > b page</div > <script > console .log(parent); parent.postMessage({ name : 'b page' }, '*' ); </script > </body >
Workers
我自己感觉很多比较麻烦耗内存的 js 逻辑操作都可以放在 worker 里,比如轮询服务器状态或者一些很耗时量很大的数据操作用
让脚本在浏览器后台线程中运行
在 worker 内,不能直接操作 DOM 节点,也不能使用 window 对象的默认方法和属性,window 对象下可用的方法
worker 中也能再创建 worker
由于安全限制 Worker 不能读取本地文件,所以脚本必须来自网络,读取本地文件会报错 “Uncaught SecurityError: Failed to create a worker: script at ‘(path)/worker.js’ cannot be accessed from origin ‘null’.”
关于兼容性
用法 在使用 worker 的 js 文件里
1 2 3 4 5 6 7 var myWorker = new Worker('worker.js' );myWorker.postMessage('request' );
在 worker.js 文件
1 2 3 4 5 6 7 onmessage = function (e ) { console .log(e.data); console .log(self); postMessage(workerResult); };
关闭/错误/加载脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 worker.terminate(); self.close(); worker.onerror(function (event ) {}); Worker.onmessageerror(function (event ) {}); importScripts('script1.js' , 'script2.js' );
小栗子 如果你现在没有条件加载网络上的文件,可以使用 URL.createObjectURL 方法建立缓存 URL 可以试着运行一下面两个页面感受一下
可以运行一下这个页面,一个普通的 for 循环,因为数字太大运行时会有明显的卡顿
1 2 3 4 5 6 7 8 9 10 11 12 13 <html > <head > <title > Test Web worker</title > <script type ="text/JavaScript" > window .onload = function ( ) { for (var num=99 ;num<1000000000 ;num++){ document .getElementById("numshow" ).innerHTML += event.data+"<br/>" ; } } </script > </head > <body id ="numshow" > </body > </html >
这个可以使用 URL.createObjectURL 方法建立缓存 URL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <html > <head > <title > Test Web worker</title > <script type ="text/JavaScript" > window .onload = function ( ) { console .log(5 ); var worker = new Worker(URL.createObjectURL(new Blob(["(" + webWorker.toString() + ")()" ], {type : 'text/javascript' }))); worker.onmessage= (event ) => { console .log(event.data); document .getElementById("numshow" ).innerHTML += event.data+"<br/>" ; event.data === 1 ? worker.postMessage('num' ):'' }; } function webWorker ( ) { console .log(self) self.onmessage = function (event ) { console .log(event.data); } for (var num = 1 ; num < 1000000000 ; num++) { num === 200 ? (postMessage("worker关闭" ), close()) : postMessage(num**2 ) } } </script > </head > <body id ="numshow" > </body > </html >
参考文章 postMessage:MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage webworker:MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers 阮一峰:http://www.ruanyifeng.com/blog/2018/07/web-worker.html