如何在(javascript)Firefox插件中有效地存储传入数据
How to store incoming data efficiently in a (javascript) firefox addon?
请求某个URL时,我想保存传入的markdown,将其转换为HTML,然后将其传递给显示。如果使用观察器,我可以获取通道,并通过 nsiTraceableChannel 将通道的侦听器设置为我的特殊"覆盖"侦听器,然后将数据传递给原始侦听器进行显示,但我很困惑此时该怎么做。onDataAvailable 方法传递一个 nsiInputStream,该流无法在 JavaScript 代码中读取。虽然我可以将其包装在 nsiScriptableInputStream 中并从中读取,但这似乎会引入大量围绕可能重复多次的简单读取操作的包装。我宁愿一次用漂亮的封闭二进制代码阅读它。
我想做的是使用 NetUtils.asyncCopy 将该输入流复制到存储流,并在完成后将存储流的结果转换为传递原始侦听器的内容。但是,这不会也继续使用 onDataAvailable 调用我的覆盖侦听器吗?文档说onDataAvalilable必须在返回之前从inputStream中准确读取那么多字节,所以我想使用nsiScriptableInputStream是强制性的吗?我是否只是从可编写脚本的输入流中读取,然后忽略并丢弃它,而异步副本在后台继续?asyncCopy 是用自己的侦听器替换我的覆盖侦听器,这很好,还是它们堆叠,这会很糟糕?
理想情况下,我想要一个接受输出流的东西,并返回一个流侦听器以传递给 nsiTraceableChannel.setInputStream,但我找不到类似的东西,甚至找不到实现 nsiStreamListener 的列表。
所以,像这样:
var {classes: Cc, interfaces: Ci, results: Cr, Constructor: CC, utils: Cu } = Components;
var hack = 3;
/*
0 = use nsiScriptableInputStream
1 = use NetUtil.asyncCopy, and then use nsiScriptableInputStream but ignore
2 = use NetUtil.asyncCopy, and it overrides our own override listener from then on
3 = use NetUtil.asyncCopy, but our own override listener keeps getting onDataAvailable, but we just ignore it
*/
var ScriptableInputStream;
if(hack == 0 || hack == 1) {
ScriptableInputStream = CC("@mozilla.org/scriptableinputstream;1","nsIScriptableInputStream", "init");
}
var StorageStream;
var NetUtil;
if(hack != 0) {
StorageStream = Cc["@mozilla.org/storagestream;1"];
Cu.import("resource://gre/modules/NetUtil.jsm");
}
function HTMLRestyler(tracingChannel) {
this.originalListener = tracingChannel.setNewListener(this);
if(hack == 0) {
this.data = "";
} else {
/* I wonder if creating one of these is as expensive as creating a
nsiScriptableInputStream for every read operation? */
this.storage = StorageStream.createInstance(Ci.nsIStorageStream);
this.storage.init(256,256,null);
this.data = this.storage.getOutputStream(0);
}
}
HTMLRestyler.prototype = {
QueryInterface: function(id)
{
if (id.equals(Components.interfaces.nsIStreamListener) ||
id.equals(Components.interfaces.nsISupportsWeakReference) ||
id.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_NOINTERFACE;
}
onDataAvailable: function(request, context, inputStream, offset, count)
{
if(hack == 0) {
var scriptStream = new ScriptableInputStream(inputStream);
this.data += scriptStream.read(count);
scriptStream.close();
/* the easy way (ow my CPU cycles) */
} else if(hack == 1) {
if(!this.iscopying) {
NetUtils.asyncCopy(inputStream,this.data,this.finished);
this.iscopying = true;
}
/* still have to read the data twice once in asyncCopy, once here
is there any point to doing this? */
var scriptStream = new ScriptableInputStream(inputStream);
var ignored = scriptStream.read(count);
scriptStream.close();
} else if(hack == 2) {
NetUtils.asyncCopy(inputStream,this.data,this.finished);
/* the "best" way
(probably doesn't work)
onDataAvailable and onStopRequest no longer called from here on,
as this listener has been overridden */
} else if(hack == 3) {
if(!this.iscopying) {
NetUtils.asyncCopy(inputStream,this.data,this.finished);
this.iscopying = true;
}
/* but no scriptable input stream needed because it's ok to just ignore
the inputStream here in the override listener and not read data*/
}
}
onStartRequest: function(request, context) {
this.request = request;
this.context = context;
},
onStopRequest: function(request, context, statusCode) {
if(hack != 2) {
this.finished(statusCode);
}
},
finished: function(status) {
this.originalListener.onStartRequest(this.request,this.context);
if(hack != 0) {
var scriptStream = new ScriptableInputStream(this.storage.newInputStream(1));
this.data = scriptStream.read(1000);
this.storage.close();
}
this.originalListener.onDataAvailable(this.transform(this.data));
this.originalListener.onStopRequest(this.request, this.context, status);
},
transform: function(data) {
return "derp "+ data;
}
}
正如您自己已经指出的那样,合同onDataAvailable
必须消耗所有数据。因此,异步 API 是不够的。
这将留下同步 API。
-
nsIStorageStream
或nsIPipe
存储数据直到完成,然后获取js-string。 -
nsIScriptableInputStream
并连接成 js 字符串 -
nsIBinaryInputStream
并连接到 js 字符串、八位字节或 ArrayBuffer。
我尝试了很多方法来有效地使用数据,onDataAvailable
DownThemAll!在我的用例中,最好在nsIPipe
的输出流端使用.writeFrom
,这不需要先将数据从C++拉入 JS 土地。
但是,您的情况可能会有所不同:您需要实际修改/转换数据,因此无论如何您都需要一个 js 字符串来进行实际转换。将数据存储在一些XPCOM流(如nsIStorageStream
或nsIPipe
)中,最终仍然会让你将整个事情读入js-stream,修改它,然后将其放回另一个流中,你可以传递给链下的下一个onDataAvailable
监听器。这意味着,您有额外的内存开销(存储流和js字符串,而不仅仅是js字符串),而实际上只节省了非常非常少的XPCOM开销。
数组缓冲区也是如此。
所以最后,考虑到你的用例,我会主张将接收到的数据直接连接成一个js字符串。但是,您应该测量时间和内存,然后决定自己进行各种选项。
当然,更有可能产生更大影响的是编写一个有状态的解析器/转换器,它不需要先缓存整个响应,而是随心所欲地进行转换。
- 如何有效地将游戏数据存储在URL查询字符串中
- 如何使用Node.js最有效地解析网页
- 如何在AngularJS中有效地检查日期是否有效
- 有效地获取两个区间之间的随机整数
- 如何在three.js中有效地使用TraingleStripDrawMode
- 如何有效地创建多维javascript数组
- 如何有效地将Float32Array插入Float32Array
- 如何有效地匹配两个不同 JavaScript 对象上的 id,并将它们合并在一起
- Javascript画布:如何有效地计算两个画布的距离
- 有效地串行化(并从nodejs读取)int数组
- 我怎样才能更有效地获取这个数字
- 我如何创建一个Chrome应用程序,有效地充当信息亭模式下的启动页面
- Javascript函数可以更有效地处理并发异步函数
- 如何更有效地重写
- 如何或如何使用firebase有效地处理错误
- 如何在(javascript)Firefox插件中有效地存储传入数据
- 有没有比 javascript 中的对象数组更有效地存储大量数据
- 如何使用 php 有效地将一个巨大的 JavaScript 字符串存储到文件中
- 有效地在内存中存储大的2d地图
- 当用户在Meteor中提交帖子时,我如何有效地存储用户的位置