博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
post-message-stream的学习-metamask
阅读量:5788 次
发布时间:2019-06-18

本文共 7738 字,大约阅读时间需要 25 分钟。

/

post-message-stream

Sets up a duplex object stream over window.postMessage  在window.postMessage上设置一个双工对象流

所以我们先学习一下window.postMessage:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage

window.postMessage

otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow:其他窗口的一个引用message:要发送的数据信息targetOrigin:该信息要发送给的目标窗口,"*" 则表示无限制。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点transfer(可选):是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

 

然后其他窗口就通过监听来接受别的窗口发来的数据:

window.addEventListener("message", receiveMessage, false);function receiveMessage(event){  // For Chrome, the origin property is in the event.originalEvent  // object.   // 这里不准确,chrome没有这个属性  // var origin = event.origin || event.originalEvent.origin;   var origin = event.origin  if (origin !== "http://example.org:8080")//如果你确实希望从其他网站接收message,请始终使用origin和source属性验证发件人的身份    return;  // ...}

message 的属性,即receiveMessage中的event:

data    从其他 window 中传递过来的对象。origin    调用 postMessage  时消息发送方窗口的 origin . 这个字符串由 协议、“://“、域名、“ : 端口号”拼接而成。例如 “https://example.org (隐含端口 443)”、“http://example.net (隐含端口 80)”、“http://example.com:8080”。请注意,这个origin不能保证是该窗口的当前或未来origin,因为postMessage被调用后可能被导航到不同的位置。source    对发送消息的窗口对象的引用; 您可以使用此来在具有不同origin的两个窗口之间建立双向通信。

 

/* * A窗口的域名是
,以下是A窗口的script标签下的代码: */var popup = window.open(...popup details...);// 如果弹出框没有被阻止且加载完成// 这行语句没有发送信息出去,即使假设当前页面没有改变location(因为targetOrigin设置不对)popup.postMessage("The user is 'bob' and the password is 'secret'", "https://secure.example.net");// 假设当前页面没有改变location,这条语句会成功添加message到发送队列中去(targetOrigin设置对了)popup.postMessage("hello there!", "http://example.org");function receiveMessage(event){ // 我们能相信信息的发送者吗? (也许这个发送者和我们最初打开的不是同一个页面). if (event.origin !== "http://example.org") return; // event.source 是我们通过window.open打开的弹出页面 popup // event.data 是 popup发送给当前页面的消息 "hi there yourself! the secret response is: rheeeeet!"}window.addEventListener("message", receiveMessage, false);
/* * 弹出页 popup 域名是
,以下是script标签中的代码: *///当A页面postMessage被调用后,这个function被addEventListenner调用function receiveMessage(event){ // 我们能信任信息来源吗? if (event.origin !== "http://example.com:8080") return; // event.source 就当前弹出页的来源页面 // event.data 是 "hello there!" // 假设你已经验证了所受到信息的origin (任何时候你都应该这样做), 一个很方便的方式就是把enent.source // 作为回信的对象,并且把event.origin作为targetOrigin event.source.postMessage("hi there yourself! the secret response " + "is: rheeeeet!", event.origin);}window.addEventListener("message", receiveMessage, false);

 

继续post-message-stream的学习

var streamA = new PostMessageStream({  name: 'thing one',  target: 'thing two',})var streamB = new PostMessageStream({  name: 'thing two',  target: 'thing one',})streamB.on('data', (data) => console.log(data))streamA.write(chunk)

 

constructor arguments

var messageStream = new PostMessageStream({  // required  // name of stream, used to differentiate  // when multiple streams are on the same window   name: 'source',  // name of target stream   target: 'sink',  // optional  // window to send the message to  // default is `window`  window: iframe.contentWindow,  })

 

其源代码:

const DuplexStream = require('readable-stream').Duplexconst inherits = require('util').inheritsmodule.exports = PostMessageStreaminherits(PostMessageStream, DuplexStream)function PostMessageStream (opts) {  DuplexStream.call(this, {    objectMode: true,//如果想创建一个的可以压入任意形式数据的可读流,只要在创建流的时候设置参数objectMode为true即可,例如:Readable({ objectMode: true })。  })  this._name = opts.name  this._target = opts.target  this._targetWindow = opts.targetWindow || window  this._origin = (opts.targetWindow ? '*' : location.origin)  // initialization flags  this._init = false  this._haveSyn = false  window.addEventListener('message', this._onMessage.bind(this), false)//监听消息  // send syncorization message  this._write('SYN', null, noop)//先将要进行第一次握手发送的SYN或收到第一次握手后发送第二次握手的syn准备好  this.cork()/强制把所有写入的数据都缓冲到内存中}// privatePostMessageStream.prototype._onMessage = function (event) {  var msg = event.data  // validate message  if (this._origin !== '*' && event.origin !== this._origin) return  if (event.source !== this._targetWindow) return  if (typeof msg !== 'object') return  if (msg.target !== this._name) return  if (!msg.data) return  if (!this._init) {//如果该流都还没有初始化,那就说明现在首先要进行三次握手来连接    // listen for handshake    if (msg.data === 'SYN') {//收到syn说明收到的是第一次握手或第二次      this._haveSyn = true      this._write('ACK', null, noop)//然后写ACK生成第二次握手或第三次发送,此时已经成功同步    } else if (msg.data === 'ACK') {//收到ACK说明收到的是第二次或第三次握手      this._init = true //说明初始化连接已经成功      if (!this._haveSyn) {//如果_haveSyn为false,那就说明收到的是第二次握手        this._write('ACK', null, noop) //所以还需要再发送一次ACK进行第三次握手      }      this.uncork()//输出被缓冲的数据    }  } else {//否则就是已经连接上了    // forward message    try {      this.push(msg.data)//将post来的数据push到流中,将调用下面的_write函数    } catch (err) {      this.emit('error', err)//出错则触发error事件    }  }}// stream plumbingPostMessageStream.prototype._read = noopPostMessageStream.prototype._write = function (data, encoding, cb) {  var message = {    target: this._target,    data: data,  }  this._targetWindow.postMessage(message, this._origin)  cb()}// utilfunction noop () {}

 

扩展知识:

(1) writable.cork() /writable.uncork()

writable.cork()

writable.cork() 方法会强制把所有写入的数据都缓冲到内存中。 当调用 stream.uncork() 或 stream.end() 方法时,被缓冲的数据才会被输出。
当写入大量小块数据到流时(因为缓存是有大小的,若都是小块数据占据了大内存,剩下的又不能装入一个数据,这样就会浪费内存),内部缓冲可能失效,从而导致性能下降,writable.cork() 主要用于避免这种情况。
writable.uncork()
writable.uncork() 方法会输出 stream.cork() 方法被调用后缓冲的全部数据。
当使用 writable.cork() 和 writable.uncork() 来管理流写入缓存,建议使用 process.nextTick() 来延迟调用 writable.uncork()。 通过这种方式,可以对单个 Node.js 事件循环中调用的所有 writable.write() 方法进行批处理。

stream.cork();stream.write('一些 ');stream.write('数据 ');process.nextTick(() => stream.uncork());

如果一个流上多次调用 writable.cork() 方法,则必须调用同样次数的 writable.uncork() 方法才能输出缓冲的数据。

stream.cork();stream.write('一些 ');stream.cork();stream.write('数据 ');process.nextTick(() => {  stream.uncork();  // 数据不会被输出,直到第二次调用 uncork()。  stream.uncork();});

 

(2)util.inherits-即nodejs的一个原型继承函数

util.inherits(constructor, superConstructor)是一个实现对象间原型继承的函数

举例说明:

var util = require('util'); function father() {     this.name = 'John'; //这为三个在构造函数中定义的属性    this.age = 1979;     this.showProperty = function() {     console.log('got five house');     }; } father.prototype.showName = function() { //这个是在原型中定义的函数    console.log(this.name);}; function son() {     this.name = 'bob';    this.age = 1997;} util.inherits(son, father); //使用util.inherits,所以son仅仅只能继承father在原型中定义的showName函数var dad = new father(); dad.showName(); dad.showProperty(); console.log(dad); var child = new son(); child.showName(); //成功// child.showProperty(); //失败console.log(child);

返回:

userdeMacBook-Pro:stream-learning user$ node test.js Johngot five housefather { name: 'John', age: 1979, showProperty: [Function] }bob

调用child.showProperty();会失败:

/Users/user/stream-learning/test.js:23child.showProperty();       ^TypeError: child.showProperty is not a function

 

(3)对想了解的可以去这个博客看看,写的很好

(4)

 

(5)readable-stream

https://github.com/nodejs/readable-stream

https://nodejs.org/dist/v10.11.0/docs/api/stream.html

Usage

You can swap your require('stream') with require('readable-stream') without any changes, if you are just using one of the main classes and functions.

const {  Readable,  Writable,  Transform,  Duplex,  pipeline,  finished} = require('readable-stream')

Note that require('stream') will return Stream, while require('readable-stream') will return Readable. We discourage using whatever is exported directly, but rather use one of the properties as shown in the example above.

 

 

 

转载于:https://www.cnblogs.com/wanghui-garcia/p/9792498.html

你可能感兴趣的文章
图片变形的抗锯齿处理方法
查看>>
Effective C++ Item 32 确保你的 public 继承模子里出来 is-a 关联
查看>>
phpstorm安装laravel-ide-helper实现自动完成、代码提示和跟踪
查看>>
python udp编程实例
查看>>
TortoiseSVN中图标的含义
查看>>
Tasks and Back stack 详解
查看>>
关于EXPORT_SYMBOL的作用浅析
查看>>
成功的背后!(给所有IT人)
查看>>
在SpringMVC利用MockMvc进行单元测试
查看>>
Nagios监控生产环境redis群集服务战
查看>>
Angular - -ngKeydown/ngKeypress/ngKeyup 键盘事件和鼠标事件
查看>>
Android BlueDroid(一):BlueDroid概述
查看>>
Java利用httpasyncclient进行异步HTTP请求
查看>>
宿舍局域网的应用
查看>>
html代码究竟什么用途
查看>>
Hadoop HDFS编程 API入门系列之路径过滤上传多个文件到HDFS(二)
查看>>
Python version 2.7 required, which was not foun...
查看>>
context:annotation-config vs component-scan
查看>>
exgcd、二元一次不定方程学习笔记
查看>>
经典sql
查看>>