小编Gar*_*ary的帖子

渐进式网络应用程序(PWA)与电子对浏览器扩展

这个问题的背景是我一直在研究我称之为工具的工具,用户可以在其中构建以后可以运行的模块.它最初只是一个小网页,并在去年增长为更接近桌面应用程序的东西; 但是,此时,仍然只是一组html,css和js文件.

我考虑使用像电子这样的东西将它打包成可安装的桌面应用程序,但我不喜欢这种方法,并认为最好坚持使用渐进式网络应用程序,因为一切都是离线完成的.

因为我想访问仅适用于Web扩展的API,所以我一直在阅读有关它们的MDN Web文档,这让我对使用PWA和浏览器扩展之间的差异感到疑惑和困惑.扩展页面运行自己的页面/程序,而不是改变浏览器中其他网页的查看和使用方式等等?

如果有人希望他们的应用离线工作并且表现得像桌面应用,那么将其作为浏览器扩展的不利之处是什么?我发现了有关PWA的更多信息,而不是浏览器扩展,给人的印象是不应以这种方式使用扩展.

看起来好处包括访问更多API,它使用自己的图标安装到浏览器中,并且可以更改扩展页面的窗口,使其看起来不在浏览器中运行.

我是stackoverflow的新手,并注意到问题有时会被关闭,因为它们被视为有争议或寻求意见而不是事实.那么,更具体一点,请您帮我理解每种方法的优缺点,和/或选择方法时应考虑的决策点?谢谢.

对答复/评论的回应

感谢您花时间回答我的问题.扩展问题包括电子是我想要避免的,并且在我的问题中提到它只是为了说明我已经广泛地审查了它并且不想再开始讨论它.我的问题只是关于PWA和浏览器扩展.

这个问题也与我申请的细节没什么关系.它已经可以作为PWA存在.问题是,如果一个应用程序已经可以作为PWA存在,那么将其作为浏览器扩展或不这样做的原因将是"坏".访问更多可用于PWA的API,并将其安装到浏览器中,使其成为"主页"似乎是一个扩展,因为缺乏更好的术语,优于PWA的环境.

关于浏览器扩展的MDN Web文档的描述包括独立游戏,但似乎鼓励整合到浏览体验中的游戏 - 无论可能是什么.我不是在构建游戏,而是想知道扩展是一个独立的工具会出现什么问题.

一位评论员似乎觉得虽然可以做到,但不应该这样做,因为扩展只是为了增强浏览体验.这可能是正确的观点.但是,另一方面,我有点想在浏览器中设置一个图标,在没有浏览器菜单的窗口中打开我的应用程序(比如运行网站全屏),并让我访问下载API.这将为我的应用程序的用户提供更好的体验.

但是可能还有其他原因不这样做,除了这不是扩展所做的事情,也不是历史上如何使用它们.是否会违反规则,让自己在以后失败,等等?或者,它是否只是为现有功能寻找另一种用途.

如果听起来那样的话,我并不想变得粗鲁,但只是想更好地澄清我的问题.谢谢.

firefox-addon google-chrome-extension progressive-web-apps pwa

8
推荐指数
1
解决办法
3572
查看次数

为什么在声明事件处理程序之前发出 indexedDB 请求?

感觉这一定是一个愚蠢的问题,但我不明白在 indexedDB 中发出请求的一些基本知识。

为什么在定义事件处理程序之前发出请求?例如,是在声明和函数request = objectStore.add(data)之前创建的。它是否正确?请求是否有可能在事件处理程序注册之前完成?request.onsuccessrequest.onerror

我将其与创建图像元素进行比较,然后声明 onload 和 onerror 的事件处理程序,所有这些都是在将 source 属性设置为文件位置并尝试加载它之前进行的。但是在发出请求之前不能创建请求“元素”;因此,在发出请求之前,没有任何事件可以附加到。

请让我知道我在这里缺少什么。我一直在毫无问题地从indexedDB中写入和检索数据,并且认为我已经正确编码了;但我想确保这是正确的并且永远有效。

谢谢。

重复响应

我不久前读过这个问题和答案,当时我第一次开始阅读有关 indexedDB 的文章,然后完全忘记了它。如果我在写这个问题之前再次找到它,我可能不会提交它,并且只会接受代码应该能够正常工作,无论我是否理解它。处理错误事件和事务中止让我再次考虑语句顺序。

然而,在再次阅读答案后,我除了接受它并希望它永远有效之外,还没有足够的理解。我并不是想挖苦。从某种意义上说,我对事件循环和纪元的思考能力有限,并且所有事情都同时发生,这只是令人困惑。

在纪元结束时(或者下一个纪元开始时,无论你认为更容易理解什么),底层 JS 引擎会返回并查看注册要执行的内容,然后几乎立即执行所有内容。

必须有一个执行顺序,否则无论异步与否,都没有任何意义。我知道解释器在开始执行下一行代码之前不会等待任何同步进程完成。但是同步语句不是按照它们在代码中出现的顺序完全依次处理,而异步语句不是按照它们在代码中出现的顺序开始处理吗?这样,如果异步过程很快出错,则可能会错过事件事件处理程序没有提前声明?事件处理程序不像函数声明那样被提升,不是吗?这是我仍然觉得困惑的部分。

在Jake Archibald 撰写的关于 Promise 的文章中,他在介绍中提供了一个有关图像加载的示例并写道:

不幸的是,在上面的示例中,事件可能发生在我们开始监听事件之前,因此我们需要使用图像的“完整”属性来解决这个问题。

在我们有机会收听之前,这不会捕获错误的图像;不幸的是 DOM 没有给我们一个方法来做到这一点。另外,这是加载一个图像,如果我们想知道一组图像何时加载,事情会变得更加复杂。

这给人的印象是顺序很重要,因此,在图像的情况下,如果可能,应在声明所有事件处理程序后分配源,以便不错过听到的事件。对我来说重要的部分是事件可以在事件处理程序被声明/注册之前发生。

我尝试遵循在 indexedDB 中声明事件处理程序后发出请求的相同模式,但这似乎不可能,因为在发出请求之前没有任何内容可以附加事件。

即使所有语句都是异步的,例如MDN Web 文档中有关使用 IndexedDB 的示例,有些事情仍然相当令人困惑objectStore.transaction.oncomplete是一个有趣的说法。我们正在等待 objectStore 创建,然后再尝试向其写入数据。(我认为在 onupgradeneeded 事件中写入数据被认为是不好的做法;因此,我们不使用该语句。)但令人困惑的是为什么我们不担心在其中创建索引之前创建 objectStore。如果所有内容都是一次性处理的,为什么 createIndex 语句不与 createObjectStore 语句同时启动?如果 createObjectStore 语句在 createIndex 语句开始之前未完成,是否应该需要事件处理程序,否则它会失败,因为 objectStore 尚不存在?

我知道它有效,因为我一直在使用相同的代码模式,但我真的不明白它。

我想更好地理解这两点——错过事件的可能性以及为什么在此 indexedDB 示例中不需要事件处理程序。我不知道这是否使我的问题有所不同,但重复问题的答案并不能为我解答这些问题。也许,我必须更好地了解 JS 引擎才能理解这些问题的答案。

const dbName = "the_name";

var request …
Run Code Online (Sandbox Code Playgroud)

javascript indexeddb

7
推荐指数
1
解决办法
829
查看次数

如何将多层对象映射到indexedDB以获得最佳效率

我的问题是在indexedDB中布局数据结构.我开始构建一个小型网页功能,这个功能已经发展成为一种网络学习工具,现在更接近于独立的渐进式Web应用程序.使用localStorage运行良好,但由于该工具已经增长,5MB限制可能会成为某些用户的问题; 所以,需要切换到indexedDB.

该应用程序仅适用于桌面,允许用户构建模块组合并将数据作为JSON字符串保存到硬盘驱动器.当用户打开(上传)在应用程序的文件,该字符串被解析并在整个投资组合写入localStorage的再次但是只有一个模块在任一个时刻写入的运行时间目标.从不同字段和索引搜索数据的角度来看,不需要"真正的"数据库,但只需要更大的存储量,因为如果投资组合中的每个模块对用户来说太混乱了必须是一个单独的文件.

保存到localStorage的大多数数据来自三级对象,并且根据用于保存和检索数据的对象路径创建密钥.例如,object.level_1 [key_1] .level_2 [key_2] .level_3 [key_3] .height = 10保存为localStorage.setItem('k1.k2.k3.h',10).

我的问题是,移动时IndexedDB的,这是比较有效:单一对象存储很像localStorage的成立,或单独的对象存储的每个三级投资组合的?

如果可以将单个objectStore视为类似于每个单独数据点的一行(一个键和一个值)的两列表,则行计数将大于三个objectStores的行计数总和,其中每一行是一个键,一个是多个数据点的对象; 但是,要更新三个objectStores之一中的单个数据点,必须将数据库对象写入临时对象,更新数据点,然后将其写回objectStore.

那么问题是,哪个更有效:在一个包含许多行的表中搜索指向一个不太复杂的值的单个唯一键,或者在三个表中搜索一个行数较少但是必须执行我认为的行相当于JSON解析,值更新和JSON stringify来更新数据库中的相同值?

尽管未明确设置限制,但单个投资组合中预期的最大level_1对象数约为25,其中每个对象最多可包含100个level_2对象,而每个对象最多可包含大约5个level_3对象.任何大于此的东西都很可能会导致用户简单地构建单独的投资组合.

因此,level_1 objectStore约为25行,level_2 objectStore约为2500行,level_3 objectStore约为12,500行.每个level_1对象有大约40个数据点; 每个level_2对象有大约100个数据点; 每个level_3对象有大约20个数据点.因此,我认为单个objectStore将具有等效于(25)(40)+(2500)(100)+(12,500)(20)= 501,000行.

我在从非常大的数据库中使用SQL提取数据方面经验丰富,但对于如何设置数据库以按键定位数据一无所知.如果必须从上到下搜索501,000行中的每一行,直到找到匹配的键,那么一个objectStore对于三个objectStore而言似乎是一个荒谬的选择.但是,如果索引资料采用比较有效的方法,然后一个对象存储可能可能取决于它是如何有效的三个objectStores中的一个的对象更新属性值是更有效的.

我不是贸易程序员; 所以,如果我的一些术语是不精确的,我会道歉并且我意识到我的问题是一个相当基本的水平; 但我无法找到任何有关如何以高效的方式将对象"映射"到对象数据库的信息.

感谢您阅读我的问题以及您可能提供的任何方向.

编辑/更新:

感谢Josh,他花时间回答我的问题并提供了许多值得思考的项目.我还没有考虑在应用程序的哪些阶段,不同类型的数据写入浏览器存储会影响对象存储数量的确定.

在用户会话期间,通常只发生两次大数据移动:从硬盘上传要解析并写入浏览器存储的JSON字符串,然后将浏览器存储读取到要进行字符串化和下载的对象中到硬盘.用户最有可能期望这两个步骤至少需要足够的时间来要求某种形式的简短进度指示器.重要的时间项是存储数据编辑和创建新数据元素所需的时间.

根据Josh的评论,或许,设置对象存储的一个好方法是考虑何时以及什么数据被屏幕写入浏览器存储,因为缺少更好的术语.在我的应用程序中,任何时候都只有一个模块(组合中的level_1对象)被加载到运行时对象中.模块级数据有一个屏幕.退出该屏幕后,模块级数据中的任何更改都将写入存储.

模块中的每个level_2对象都有自己的屏幕,当用户在level_2对象屏幕之间导航时,将根据运行时对象的更改值检查屏幕输入元素中的内容,并将任何更改写入存储.

在level_2对象屏幕上,用户通过调用出现在level_2屏幕顶部的窗口,将level_3对象添加到特定的level_2元素.当每个窗口关闭时,执行类似的检查,并将任何数据更改写入存储.

创建与每个屏幕上显示和收集的数据对齐的对象存储似乎是有意义的,当然,与对象级别对齐.但是,它仍然无法回答哪种数据结构最有效,从而提供最佳的用户体验.

除了数据库效率的某些经验法则之外,针对我的特定问题和环境的可能最佳方法是以两种方式对其进行编码,使用大于预期数量的最大模块填充组合,以及level_2和level_3对象,并进行测试写入和读取数据到indexedDB的性能.单个对象存储的第一种方法应该相当容易编码,因为它的设置几乎与localStorage完全相同.使用至少三个对象存储库的第二种方法将花费更多时间,但对于我在这些领域具有有限背景的人来说,这可能是必要且有价值的学习体验.

如果我成功了,我将在不久的将来在这里分享结果.谢谢.

编辑:

感谢您的进一步解释.我不打算以这种方式查询数据库,而是仅存储基于唯一键的检索数据.但是,您之前关于在多个表中存储相同数据的评论最终在我的脑海中注册,我认为这大大简化了我的整个问题和方法.从本地存储的角度来看,我的想法太多了.

我认为可以正常工作的是多个对象存储:一个对象存储包含每个模块的一个完整对象或组合中的level_1数据,以及三个或四个对象存储,其中包含仅用于"活动"或已加载模块的数据子集.

当用户选择要加载的模块时,它将在一个步骤中从模块对象存储器完整地加载它,并且该模块的子集(不同的对象级别)将被写入多个不同的对象存储器.当用户在任何级别编辑模块数据时,编辑将存储在适当的子集对象存储中,因为这将更快.

如果用户正确地退出/关闭模块,那么此时加载的对象将被完整地写入模块对象存储,并且子集对象存储将被清空.子集对象存储用于在用户未能正确退出或存在电源或操作系统故障的情况下保留更改.

打开应用程序时,将测试浏览器存储以确定是否存在数据库,如果存在,则确定子集对象存储是否为空.如果为空,则执行适当的关闭和保存模块.如果不为空,则无论出于何种原因,对模块的编辑都没有进入模块对象存储区,并且系统会提示用户恢复或放弃保存在子集对象库中的编辑.如果用户选择恢复,则子集对象存储中的数据必须一起收集到一个完整的模块中并写入模块对象存储.

对于此应用程序中任何单个模块的预期最大大小,这应该可以正常工作; 但是如果模块的大小在整个加载时对于浏览器变得太大,那么子集对象存储可以用于填充屏幕; 当用户退出模块时,子集可以聚集在一起构建一组完整的模块数据并写入模块对象存储库,就像恢复一样.

当然,如果浏览器由于模块过大而运行得太慢并且在那时改变了方法,则无法在运行时进行测试.我的意思是,如果在我测试大型样本模块时,观察到浏览器运行速度太慢,那么需要实现第二种方法.

我意识到我的特定问题并不像响应中列出的项目那么有趣.但是,阅读这些一般概念有助于我更好地理解如何解决我对indexedDB的不那么有趣的使用,并避免在为简单问题编写不必要的复杂性时会产生大量麻烦.再次感谢.

indexeddb

5
推荐指数
1
解决办法
385
查看次数

两个 textarea 元素是否可以“链接”到相同的本机输入事件,而不是在每个 addEventListener 输入事件上复制值?

有没有办法将两个textarea元素“链接”到相同的本机输入事件?我知道我可以将value一个的设置为另一个的;并了解到这也可以在CSS 技巧中使用伪元素来完成,但每种方法似乎都会在每个按键事件上将整个字符串从“活动”文本区域重写为“复制”文本区域。

有没有办法像文本编辑器中同一文件的拆分视图一样链接它们?我真的不知道它在文本编辑器中是如何工作的,但我一直在分割视图中处理一些大文件,它们更新每个关键事件的全部内容而不是仅仅将它们链接在一起似乎很奇怪。

感谢您考虑我的问题。

html javascript

5
推荐指数
1
解决办法
51
查看次数

对象序列化到 indexedDB 与 JSON.stringify 的效率

我对 JSON.stringify 的序列化步骤与将对象写入 indexedDB 中的对象存储的序列化步骤之间在浏览器/CPU/内存效率方面的差异感兴趣。

该问题的动机或上下文是以最有效的方式将对象从数据库写入客户端的硬盘驱动器。为此,使用 get 语句检索对象并将其写入对象,该对象使用 JSON.stringify 转换为字符串,然后作为文本写入磁盘。我假设 get 语句将对象从数据库中的序列化形式反序列化。如果是这样,则该对象将从 indexedDB 形式反序列化,然后序列化为 JSON.stringify 形式。

然后,为了从磁盘恢复数据,读取文件,使用 JSON.parse 将文本转换为对象,并将该对象添加或放入数据库中,这似乎需要另一个序列化步骤。因此,JSON字符串被解析为一个对象,然后序列化为indexedDB形式。

我的问题的第一部分是可以以序列化形式从数据库中检索对象,以便可以以相同的形式将其保存到磁盘并再次写入数据库,而无需执行字符串化/解析的中间步骤?

问题的第二部分是,如果不可能这样做,并且对于使用没有任何索引的indexedDB并且从不通过除外线唯一键之外的任何值查询数据的特殊情况,是否有任何优势将字符串化对象存储到数据库而不是对象?

在这种情况下,写入/读取磁盘不会涉及中间的字符串化/解析步骤,并且当字符串在数据库中获取/放入时不会有反序列化/序列化步骤,因为它不是对象。但是,要更改数据库中这些字符串之一中的值,需要对 get 的结果执行 JSON.parse 以将其转换为对象,然后在更改值后将字符串放回数据库之前执行 JSON.stringify数据库。

但是,当对对象使用 get 和 put 时,JSON.parse 和 JSON.stringify 与数据库对象的反序列化和重新序列化相比如何呢?我认为将对象序列化到 indexedDB 需要的不仅仅是 JSON.stringify,因为前者可以通过其属性进行查询。

我将进行实验,看看是否可以观察到差异,但想询问了解两种类型序列化内部工作原理的人,在这种情况下是否存在根本原因,需要使用一种方法而不是另一种方法。

编辑

显然,如果我理解正确的话,结构化克隆算法用于在indexedDB中存储对象;但该结果在存储之前仍然是序列化的吗?JSON 使用词法语法但从不复制对象。

也许,我只是很困惑,写入 indexedDB 时没有序列化步骤,而且我观察到 RAM 使用量的增加是为了克隆对象,然后将其存储为对象。如果是这样,那么问题的第一部分根本没有意义,因为数据库对象始终需要转换为字符串才能保存到磁盘。我的问题的第二部分将成为对浏览器的要求更高,1)将对象转换为字符串或克隆它,2)从数据库检索对象与检索字符串(如果保存为 JSON 字符串)并解析它?

在找到更多有关此问题的信息后,尽管其中大部分内容超出了我的理解范围,但我不确定这个问题是否值得考虑。

谢谢。

例子:

@Sam152你是说你发现,在类似下面的内容中,stingify版本比仅仅将对象放入数据库更快?第一个示例是五十个事务的间隔,第二个示例是put单个事务中的五十个事务。

// var o = A large object.
var d;
write.x = 0;
write.y=[];

DB_open().then( inter );

function inter() { d = setInterval( write, 1000 ); …
Run Code Online (Sandbox Code Playgroud)

javascript json indexeddb

4
推荐指数
1
解决办法
2821
查看次数

将文件写入客户端磁盘时从 blob 创建/对象 URL 中释放内存

更新

由于提出了下面的问题并在发现代码中的错误后得出了一个更基本的问题,我发现了更多信息,例如在 MDN Web 文档中的下载 API 方法 downloads.download() 中,它指出对象的撤销url 仅应在文件/url 下载后执行。因此,我花了一些时间试图了解 Web 扩展是否使下载 API onChanged 事件对网页的 javascript“可用”,但我认为不会。我不明白为什么下载 API 仅适用于扩展程序,特别是当存在很多与内存使用/对象 url 撤销问题有关的问题时。例如,等待用户完成 JavaScript 中的 blob 下载

如果你知道的话请解释一下吗?谢谢。


从关闭的 Firefox 浏览器开始,右键单击要在 Firefox 中打开的本地 html 文件,它将打开并显示五个 firefox.exe 进程,如 Windows 任务管理器中所示。其中四个进程的启动内存介于 20,000k 到 25,000k 之间,一个进程的内存约为 115,000k。

此 html 页面有一个 indexedDB 数据库,其中有 50 个对象存储,每个存储包含 50 个对象。每个对象都从其对象存储中提取并使用 JSON.stringify 转换为字符串,然后写入二维数组。然后,数组的所有元素被连接成一个大字符串,转换为一个 blob,并通过 URL 对象写入硬盘,该对象随后立即被撤销。最终文件大约190MB。

如果代码在转换为 blob 之前停止,则 firefox.exe 进程之一的内存使用量会增加到大约 425,000k,然后在数组元素连接成一个数组后大约 5-10 秒内回落到 25,000k。单字符串。

如果代码运行完成,同一 firefox.exe 进程的内存使用量将增长到大约 1,000,000k,然后下降到大约 225,000k。以 115,000k 启动的 firefox.exe 进程也在代码的 blob 阶段增加到约 …

javascript memory-leaks blob revokeobjecturl

3
推荐指数
1
解决办法
7858
查看次数

Proper way to break out of an if block in JavaScript?

In an if block structure, such as below, suppose that condition_1 and condition_2 are mutually exclusive but there are times when condition_2 and later conditions can both be true; and, when condition_2 is true, all that is desired is to break out of the if block and continue with the rest of the code, similar to a switch statement.

All the conditions, except condition_2, are matches statements for a listener on a parent container with several buttons. When condition_2 is …

javascript if-statement break

3
推荐指数
1
解决办法
48
查看次数