gpt4 book ai didi

javascript - 如何在(javascript)firefox插件中有效存储传入数据?

转载 作者:行者123 更新时间:2023-12-02 16:33:15 26 4
gpt4 key购买 nike

在请求某个 URL 时,我想保存传入的 Markdown,将其转换为 HTML,然后将其传递以进行显示。如果使用观察者,我可以获取 channel ,并通过 nsiTraceableChannel 将 channel 的监听器设置为我的特殊“覆盖”监听器,然后将数据传递给原始监听器进行显示,但我很困惑此时该怎么做。 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;
}
}

最佳答案

正如您已经指出的那样,契约(Contract)的 onDataAvailable 必须消耗所有数据。因此,异步 API 是不够的。

这就留下了同步 API。

  1. nsIStorageStreamnsIPipe 存储数据直至完成,然后获取 js-string。
  2. nsIScriptableInputStream 并连接成 js 字符串
  3. nsIBinaryInputStream 并连接成 js 字符串、八位字节或 ArrayBuffer。

我尝试了很多方法来有效地使用 DownThemAll! 的 onDataAvailable 中的数据。在我的用例中,最好在 nsIPipe 的输出流端使用 .writeFrom,这不需要将数据从 C++ 提取到 JS 领域首先。

但是,您的情况可能有所不同:您需要实际修改/转换数据,因此无论如何您都需要一个 js 字符串来进行实际转换。将数据存储在一些 XPCOM 流中,例如 nsIStorageStream 或 nsIPipe ,最终您仍然会将整个内容读入 js 流,修改它,然后将其放回到另一个流中您可以将其传递给链上的下一个 onDataAvailable 监听器。这意味着,您有额外的内存开销(存储流和 js 字符串,而不仅仅是 js 字符串),而实际上只节省了非常非常少的 XPCOM 开销。

数组缓冲区也是如此。

所以最后,考虑到您的用例,我建议将接收到的数据直接连接到 js 字符串中。但是,您应该自己测量各种选项的时间和内存使用情况,然后做出决定。

当然,更可能产生更大影响(特别是对于内存使用)的是编写一个有状态的解析器/转换器,它不需要先缓存整个响应,而是随时进行转换。

关于javascript - 如何在(javascript)firefox插件中有效存储传入数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28135113/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com