用JavaScript构建大字符串;连接方法最有效吗?

时间:2018-06-21 21:21:37

标签: javascript arrays string

在将数据库作为JSON字符串的文本文件写入磁盘时,我一直在尝试如何最有效地构建文本字符串,最终将其转换为blob以下载到磁盘。

有许多问题表明,不是在循环中使用+运算符来连接字符串,而是将组件字符串写入数组,然后使用join方法来构建一个大数组。字符串。

我在Jeol Mueller的here中找到了解释原因的最佳解释:

  

在JavaScript(以及C#)中,字符串是不可变的。它们永远无法更改,只能替换为其他字符串。您可能知道,组合+“ hello”不会直接修改组合变量-该操作将创建一个新字符串,这是将两个字符串连接在一起的结果,但是如果出现以下情况,则必须将该新字符串分配给组合变量您想要更改它。

     

因此,此循环正在执行的操作是创建一百万个不同的字符串对象,并丢弃其中的999,999个。创建这么多大小不断增长的字符串并不是很快,现在垃圾回收器需要大量工作来清理。”

thread here也很有帮助。

但是,使用join方法不允许我在没有错误的情况下构建目标字符串:

  

分配大小溢出

我试图将50,000个JSON字符串从数据库写入一个文本文件,无论如何它可能太大了。我认为它已超过350MB。我只是在测试应用程序的限制,并选择了比应用程序用户可能创建的东西大得多的东西。因此,该测试用例可能不合理。

尽管如此,这给我留下了三个有关处理大字符串的问题。


  1. 对于总体上相同数量的数据,改变单个join操作中联接的数组元素的数量是否会影响分配效率,而不会遇到分配大小溢出的问题?

    例如,我尝试将JSON字符串写入每个维度包含100个(然后是50个)元素的伪3-D数组。然后遍历外部二维将它们连接在一起。 100 ^ 3 = 1,000,000或50 ^ 3 = 125,000都提供了足够多的条目来容纳50,000个JSON字符串。我知道我这里不包括0索引。

    因此,第一次尝试将50,000个字符串保存在从a [1] [1] [1]到a 5 [100] [100]和a [1] [1]的数组中第二次尝试中将[1]设置为[20] [50] [50]。如果尺寸是从外到内的i,j,k,则我将每个a [i] [j]中的所有k个元素连接在一起;然后将所有这些i x j联接加入,最后将所有这些i联接到最终的文本字符串中。

    在完成之前,所有attemtps仍然达到分配大小溢出

    因此,如果总数据相同,则将50,000个较小的字符串合并成一个join与50个较大的字符串之间有什么区别吗?


  1. 是否有比join方法更好,更有效的方式来构建大型字符串?

  1. 乔尔·穆勒(Joel Mueller)关于字符串连接的相同原则是否适用于通过substring来简化字符串,例如string = string.substring(position)

    第三个问题的上下文是,当我以字符串形式读取文本文件并将其分解为组件JSON字符串,然后再写入数据库时​​,我使用的是文件布局图的数组;因此,我提前知道了每个JSON字符串的长度,并在循环内重复了三个语句:

    l = map[i].l;
    str = text.substring(0,l);
    text = text.substring(l).  
    

    由于字符串是不可变的,因此这种反向串联步骤的效率与使用+运算符进行串联一样低。

    在每次迭代中不删除文本中的str,而是跟踪整个字符串的整个循环,仅跟踪子字符串的开始和结束位置的增加,是否会更有效?

回复有关重复问题的消息

我想从stackoverflow系统本身收到一条消息,要求我编辑我的问题,解释为什么它与建议的重复项不同。

原因是:

  1. 建议的重复项专门且唯一地询问单个字符串的最大大小。尽管知道这很有用,但是三个粗体问题都没有询问单个字符串的最大大小。

  2. 此问题询问构建大型字符串的最有效方法,除了有效的构建大型测试字符串的方法以外,在所提出的重复项中找不到答案。他们没有解决如何构建由实际应用程序数据组成的逼真的字符串。

  3. 这个问题提供了一些链接,指向一些有关构建大型字符串的效率的信息,这些信息可能对那些感兴趣的人不仅仅限于最大大小。

  4. 该问题还具有特定的上下文,说明为什么要构建大字符串,这导致了有关如何以更有效的方式处理这种情况的一些建议。尽管从最严格的意义上讲,它们并没有按标题专门解决问题,但它们确实解决了所提出问题的更广泛上下文,即如何处理大字符串,即使这意味着解决它们的方法。在同一主题上进行搜索的人可能会在这些建议中找到真正的帮助,而建议的重复项中未提供这些帮助。

因此,尽管建议的重复项在一定程度上有所帮助,但在整个上下文中似乎都没有接近该问题的真实重复项。

其他信息

这不能回答有关构建大字符串的最有效方法的问题,但它涉及有关如何绕过字符串大小限制的注释。

将每个组件字符串转换为blob并将其保存在数组中,然后将blob数组转换为单个blob,即可完成此操作。我不知道单个Blob的大小限制是多少,但是在另一个问题中确实看到了800MB。

可以找到用于创建Blob的过程(或起点),以将数据库写入磁盘,然后再次将其读回。here

关于在客户端上生成Blob或字符串时将它们写入磁盘的想法,而不是生成一个巨型字符串或Blob进行下载的想法,尽管在这种情况下,最逻辑和最有效的方法可能无法实现脱机应用程序。

根据此question,Web扩展不再可以访问通过File API完成此操作所需的特权javascript代码。

我问了这个question与Streams API写入流方法以及称为StreamSaver的东西有关。

1 个答案:

答案 0 :(得分:2)

  

将数据库作为JSON字符串的文本文件写入磁盘时。

在这种情况下,我认为没有理由将数据存储在字符串或字符串数​​组中。相反,您可以将数据直接写入文件。

  • 在最简单的情况下,您可以将每个字符串分别写入文件。
  • 要获得更好的性能,您可以先将一些数据写入较小的缓冲区,然后在缓冲区已满时将其写入磁盘。
  • 为了获得最佳性能,您可以创建一定大小的文件,并在该文件上创建内存映射。然后将数据直接写入/复制到映射的内存(即您的文件)中。诀窍是先知道或猜测大小,也可以在需要时调整文件大小,然后重新映射文​​件。

连接或增长字符串将触发大量内存(重新)分配,在这种情况下,这是不必要的开销。


  

我不希望用户下载多个文件

如果目标是让用户下载生成的文件,则可以直接将这些字符串流传输给用户而无需创建文件,甚至可以做得更好。这样做的好处还在于,用户可以立即开始接收数据,而不必首先等到整个文件生成之后。

由于文件大小未知,可以使用chunked transfer encoding

相关问题