kumavis/post-message-stream

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窗口的域名是<http://example.com:8080>,以下是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 域名是<http://example.org>,以下是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').Duplex
const inherits = require('util').inherits module.exports = PostMessageStream inherits(PostMessageStream, DuplexStream) function PostMessageStream (opts) {
DuplexStream.call(this, {
objectMode: true,//如果想创建一个的可以压入任意形式数据的可读流,只要在创建流的时候设置参数objectModetrue即可,例如: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()/强制把所有写入的数据都缓冲到内存中
} // private
PostMessageStream.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 plumbing
PostMessageStream.prototype._read = noop PostMessageStream.prototype._write = function (data, encoding, cb) {
var message = {
target: this._target,
data: data,
}
this._targetWindow.postMessage(message, this._origin)
cb()
} // util function 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 = ;
this.showProperty = function() {
console.log('got five house');
};
}
father.prototype.showName = function() { //这个是在原型中定义的函数
console.log(this.name);
};
function son() {
this.name = 'bob';
this.age = ;
}
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
John
got five house
father { name: 'John', age: , showProperty: [Function] }
bob

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

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

(3)对JavaScript prototype 使用介绍想了解的可以去这个博客看看,写的很好

(4)javascript:apply方法 以及和call的区别 (转载)

(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.


post-message-stream的学习-metamask的更多相关文章

  1. nodejs stream 手册学习

    nodejs stream 手册 https://github.com/jabez128/stream-handbook 在node中,流可以帮助我们将事情的重点分为几份,因为使用流可以帮助我们将实现 ...

  2. pump模块的学习-metamask

    pump = require('pump') pump简介 https://github.com/terinjokes/gulp-uglify/blob/master/docs/why-use-pum ...

  3. gulp学习-metamask前端使用

    https://www.gulpjs.com.cn/docs/getting-started/ ,这个是3.9.0版本 后面发现安装的版本是4.0.0,看下面这个: https://github.co ...

  4. Java_lambda表达式之"stream流学习,Map学习,collect学习,Conllectors工具类学习"

    Lambda表达式学习 对List<Integer> userIdList = UserList.stream().map(User::getUserId).collect(Collect ...

  5. java I/O Stream 代码学习总结

    一. InputStream 类学习介绍 mark方法 public void mark(int readlimit) 在此输入流中标记当前的位置.对 reset 方法的后续调用会在最后标记的位置重新 ...

  6. Node.js stream 流学习

    由于node.js 创建http 是这样的 http.createServer(function(request,response){}).listen(2000); 里面的request 就是rea ...

  7. 流Stream个人学习理解

    1.Stream类 命名空间:System.IO 程序集:mscorlib 流是对字节序列的抽象,提供字节序列的一般视图. 流的操作包括三个方面: 1.读取(Read):将流数据传入到数据结构 2.写 ...

  8. Java 8中Stream API学习笔记

    1)函数式编程的优势和劣势分别是什么?优势:①不可变性 ②并行操作 ③执行顺序更灵活 ④代码更加简洁纯粹的函数式编程,变量具有不可变性,同一个参数不会在不同场景下得出不同的结果,因此大大增强了系统的稳 ...

  9. Java8 新特性Stream 的学习和使用方法

    流(Stream) 流是java 8 中新引入的特性,用来处理集合中的数据,Stream 是一个来自数据源的元素队列并支持聚合操作. Java 中 Stream 不会存储元素. 数据源 流的来源. 可 ...

随机推荐

  1. 放苹果(poj1664递归)

    ti放苹果 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 24392   Accepted: 15513 Descripti ...

  2. 让你彻底搞懂JS中复杂运算符==

    让你彻底搞懂JS中复杂运算符== 大家知道,==是JavaScript中比较复杂的一个运算符.它的运算规则奇怪,容易让人犯错,从而成为JavaScript中“最糟糕的特性”之一. 在仔细阅读了ECMA ...

  3. windows 公司内部搭建禅道(项目管控)

    禅道的搭建异常爽快,非常方便,一般情况下我们使用开源版就可以了.下面是搭建流程,这里主要记录一些前期的注意事项 使用一键安装版就可以,很快,禅道安装主机安装好所需的Apache容器和mysql数据库, ...

  4. HTML页面局部刷新

    /.事件响应刷新:有请求才会刷新 1.通过JS HTML DOM或jQuery获取HTML元素,通过DOM方法或jQuery方法监听页面事件,获取用户请求: 2.通过Ajax将用户请求提交至服务器,服 ...

  5. cf97D. Robot in Basement(模拟 bitset)

    题意 题目链接 Sol 接下来我的实现方式和论文里不太一样 然后用bitset优化,上下走分别对应着右移/左移m位,左右走对应着右移/左移1位 我们可以直接预处理出能走的格子和不能走的格子,每次走的时 ...

  6. easyui+webuploader+ckeditor实现插件式多图片上传

    需求:在ckeditor编辑器上实现多图片上传并要求另外单独选择ckeditor上传的图片作为封面 页面效果说明: 动态效果图: 第一步:页面布局 <html xmlns="http: ...

  7. AngularJS学习之 angular-file-upload控件使用方法

    1.官方链接 https://github.com/nervgh/angular-file-upload 2.安装到项目中 bower install angular-file-upload(安装完成 ...

  8. arm64 调试环境搭建及 ROP 实战

    前言 比赛的一个 arm 64 位的 pwn 题,通过这个题实践了 arm 64 下的 rop 以及调试环境搭建的方式. 题目文件 https://gitee.com/hac425/blog_data ...

  9. CVE-2018-15688 systemd dhcp6组件越界写漏洞分析

    编译的话 , 用 ubuntu 18.10, 没有 patch 的源码下载路径 https://codeload.github.com/poettering/systemd/zip/3941f8329 ...

  10. Vue入门(二)之数据绑定

    Vue官网: https://cn.vuejs.org/v2/guide/forms.html#基础用法 [入门系列] (一)  http://www.cnblogs.com/gdsblog/p/78 ...