Javascript V8引擎与Blob对象

JavaScript V8引擎

V8 是驱动 Google Chrome 的 JavaScript 引擎的名称。

V8 提供了 JavaScript 执行的运行时环境。 DOM 和其他 Web 平台 API 由浏览器提供。

V8的内存限制

在64位系统下约为1.4 GB,32位系统下约为0.7 GB。

V8为什么要限制堆的大小?

  • 表层原因:V8最初是为浏览器设计的,不太可能遇到使用大量内存的场景。
  • 深层原因:V8的垃圾回收机制的限制。

V8的对象分配

在V8中,所有的JavaScript对象都是通过堆来进行分配的。

img

当在代码中声明变量并赋值时,所使用对象的内存就分配在堆中。如果已经申请到的堆空闲内存不够分配新的对象,将继续申请堆内存,直到堆的大小超出V8的限制为止。

V8的垃圾回收机制

V8的垃圾回收策略主要基于分代式垃圾回收机制,把内存分为新生代和老生代。

分代式垃圾回收机制:按照对象的存活时间将内存的垃圾回收进行不同的分代,然后分别对不同的分代的内存实施更高效的回收算法。

新生代:新生代中的对象为存活时间较短的对象,采用复制算法(内存一分二,分为From和To)。

老生代:老生代中的对象为存活时间较长或常驻内存的对象,使用标记清除和标记整理算法。

img

新生代中的垃圾回收

img

新生代中的对象主要通过Scavenge算法进行垃圾回收,Scavenge算法在具体实现上采用Cheney算法。

大致过程为:将堆内存一分为二,每一部分空间称为semispace。在这两个semispace中,只有一个空间处于使用中,另一个处于空闲状态。处于使用状态的空间称为From空间,空闲状态的空间称为To空间。分配对象时,现在From空间进行分配。当开始进行垃圾回收时会检查From空间中的存活对象,这些存活对象会被分配到To空间中,而非存活对象占用的空间将被释放。完成释放后,From空间和To空间的角色发生对换。简而言之,就是将存活对象在两个空间中来回复制。

对象晋升

当一个对象经过多次复制依然存活时,将会被认为是生命周期较长的对象。这种对象随后会被移动到老生代中(对象晋升),采用新的算法进行管理。

对象晋升的条件:

  • 对象是否经理过Scavenge回收。
  • To空间的内存用比是否超过限制。

在默认情况下,V8的对象分配主要集中在From空间中。对象从From空间中复制到To空间时,会检查它的内存地址来判断这个对象是否已经经历过一次Scavenge回收。如果已经经历过了,会将该对象从From空间复制到老生代空间中,如果没有,则复制到To空间中。

img

另一个判断条件是To空间的内存占用比。当要从From空间复制一个对象到To空间时,如果To空间已经使用了超过25%,则这个对象直接晋升到老生代空间中。之后From和To地位互换。

img

老生代中的垃圾回收

对象晋升后,在老生代中接收新的回收算法处理。

V8在老生代中主要采用Mark-Sweep(标记清除)和Mark-Compact(标记整理)相结合的方式进行垃圾回收。

Mark-Sweep分为两个阶段:标记和清除。

在标记阶段遍历堆中所有对象,并标记活着的对象,在随后的清理阶段中,只清理没有被标记的对象,即只清理死亡的对象。如下图: 黑色部分为标记死亡的对象。

img

Mark-Sweep最大的问题是在进行一次标记清除回收后会造成内存空间的不连续。这种内存碎片会对后续的内存分配造成问题。例如:此时,当需要分配一个比较大的对象时,所有的碎片空间都无法完成此次分配,就会提前触发垃圾回收,而此时的回收是不必要的。

为解决Mark-Sweep后的内存碎片化问题,Mark-Compact(标记-整理)被提出。Mark-Compact在整理阶段将活的对象向一端移动,移动完成后,直接清理掉边界外的内存。如下图所示,白色格子为存活对象,深色格子为死亡对象,浅色格子为存活对象移动后留下的空洞。

img

在V8的回收策略中,Mark-Sweep和Mark-Compact是结合使用的。主要使用Mark-Sweep,在不足以对从新生代中晋升过来的对象进行分配时才会使用Mark-Compact。

img

Incremental Marking(增量标记)

为了避免出现JavaScript应用逻辑与垃圾回收器看到的不一致的情况,垃圾回收的3种基本算法都需要将应用逻辑暂停下来,待执行完垃圾回收后再恢复执行应用逻辑,这种行为被称为“全停顿”(stop-the-world)。

在V8的分代式垃圾回收中,一次小垃圾回收只收集新生代,由于新生代默认配置得较小,且其中存活对象通常较少,所以即便它是全停顿的影响也不大。但V8的老生代通常配置得较大,且存活对象较多,全堆垃圾回收(full 垃圾回收)的标记、清理、整理等动作造成的停顿就会比较可怕,需要设法改善。

为了降低全堆垃圾回收带来的停顿时间,V8先从标记阶段入手, 将原本要一口气停顿完成的动作改为增量标记(Incremental Marking),也就是拆分为许多小“步进”,每做完一“步进”就让JavaScript应用逻辑执行一小会儿,垃圾回收与应用逻辑交替执行直到标记阶段完成。

img

V8后续还引入了延迟清理(lazy sweeping)与增量式整理(incremental compaction),让清理与整理动作也变成增量式的。同时还计划引入并行标记与并行清理,进一步利用多核性能降低每次停顿的时间。

前端Blob对象

Blob 对象表示一个不可变、原始数据的类文件对象。Blob对象中的数据并不一定得是JavaScript中的原生形式。File接口基于Blob,继承了Blob的功能,并且扩展支持了用户计算机上的本地文件。

Blob(Binary Large Object)对象代表了一段二进制数据,提供了一系列操作接口。其他操作二进制数据的 API(比如 File 对象),都是建立在 Blob 对象基础上的,继承了它的属性和方法。

通过构造函数创建Blob对象

var blob = new Blob(dataArr:Array, opt:{type:string});

  • dataArray:数组,包含了要添加到Blob对象中的数据,数据可以是任意多个ArrayBuffer,ArrayBufferView, Blob,或者 DOMString对象。
  • opt:对象,用于设置Blob对象的属性(如:MIME类型)

1、创建一个装填DOMString对象的Blob对象
img

2、创建一个装填ArrayBuffer对象的Blob对象
img

3、创建一个装填ArrayBufferView对象的Blob对象(ArrayBufferView可基于ArrayBuffer创建,返回值是一个类数组。如下:创建一个8字节的ArrayBuffer,在其上创建一个每个数组元素为2字节的“视图”)
img

Javascript 之 ArrayBuffer: https://www.cnblogs.com/chris-oil/p/8615559.html

slice() 方法原本接受 length 作为第二个参数,以表示复制到新 Blob 对象的字节数。如果设置的参数使 start + length 超出了源 Blob 对象的大小,则返回从开始到结尾的所有数据。

slice() 方法在某些浏览器和版本上带有浏览器引擎前缀:比如 Firefox 12 及更早版本的blob.mozSlice() 和 Safari 中的blob.webkitSlice()。 没有浏览器引擎前缀的老版本 slice() 方法有不同的语义,并且已过时。Firefox 30 取消了对 blob.mozSlice() 的支持。

属性
  • Blob.isClosed (只读)

    布尔值,指示 Blob.close() 是否在该对象上调用过。 关闭的 blob 对象不可读。

  • Blob.size (只读)

    Blob 对象中所包含数据的大小(字节)。

  • Blob.type (只读)

    一个字符串,表明该Blob对象所包含数据的MIME类型。如果类型未知,则该值为空字符串。

方法
  • Blob.close()

    关闭 Blob 对象,以便能释放底层资源。

  • Blob.slice([start[, end[, contentType]]])

    返回一个新的 Blob 对象,包含了源 Blob 对象中指定范围内的数据。其实就是对这个blob中的数据进行切割,我们在对文件进行分片上传的时候需要使用到这个方法。

看到上面这些方法和属性,使用过HTML5提供的File接口的应该都很熟悉,这些属性和方法在File接口中也都有。 其实File接口就是基于Blob,继承blob功能并将其扩展为支持用户系统上的文件,也就是说:

File接口中的Flie对象就是继承与Blob对象。

使用场景
1、文件分片上传

首先说说分片上传,我们在进行文件上传的时候,因为服务器的限制,会限制每一次上传到服务器的文件大小不会很大,这个时候我们就需要把一个需要上传的文件进行切割,然后分别进行上传到服务器。

假如需要做到这一步,我们需要解决两个问题:

  • 怎么切割?
  • 怎么得知当前传输的进度?

首先怎么切割的问题上面已经有过说明,因为File文件对象是继承与Blob对象的,因此File文件对象也拥有slice这个方法,我们可以使用这个方法将任何一个File文件进行切割。

代码如下:

var BYTES_PER_CHUNK = 1024 * 1024; // 每个文件切片大小定为1MB .
var blob = document.getElementById("file").files[0];
var slices = Math.ceil(blob.size / BYTES_PER_CHUNK);
var blobs = [];
slices.forEach(function(item, index) {
   
    blobs.push(blob.slice(index,index + 1));
});

通过上面的方法。我们就得到了一个切割之后的File对象组成的数组blobs;

接下来要做的时候就是讲这些文件分别上传到服务器。

在HTTP1.1以上的协议中,有Transfer-Encoding这个编码协议,用以和服务器通信,来得知当前分片传递的文件进程。

这样解决了这两个问题,我们不仅可以对文件进行分片上传,并且能够得到文件上传的进度。

Transfer-Encoding: https://blog.csdn.net/liuxiao723846/article/details/107432433

2、粘贴图片

blob还有一个应用场景,就是获取剪切板上的数据来进行粘贴的操作。例如通过QQ截图后,需要在网页上进行粘贴操作。

粘贴图片我们需要解决下面几个问题

  1. 监听用户的粘贴操作
  2. 获取到剪切板上的数据
  3. 将获取到的数据渲染到网页中

首先我们可以通过paste事件来监听用户的粘贴操作:

document.addEventListener('paste', function (e) {
   
    console.info(e);
});

然后通过事件对象中的clipboardData 对象来获取图片的文件数据。

clipboard对象: https://www.ruanyifeng.com/blog/2021/01/clipboard-api.html

clipboardData对象介绍

介绍一下 clipboardData 对象,它实际上是一个 DataTransfer 类型的对象, DataTransfer 是拖动产生的一个对象,但实际上粘贴事件也是它。

clipboardData 的属性介绍
属性 类型 说明
dropEffect String 默认是 none
effectAllowed String 默认是 uninitialized
files FileList 粘贴操作为空List
items DataTransferItemList 剪切板中的各项数据
types Array 剪切板中的数据类型 该属性在Safari下比较混乱
items 介绍

items 是一个 DataTransferItemList 对象,自然里面都是 DataTransferItem 类型的数据了。

属性

items 的 DataTransferItem 有两个属性 kind 和 type

属性 说明
kind 一般为 string 或者 file
type 具体的数据类型,例如具体是哪种类型字符串或者哪种类型的文件,即 MIME-Type
方法
方法 参数 说明
getAsFile 如果 kind 是 file ,可以用该方法获取到文件
getAsString function(str) 如果 kind 是 string ,可以用该方法获取到字符串str

在原型上还有一些其他方法,不过在处理剪切板操作的时候一般用不到了。

type 介绍

一般 types 中常见的值有 text/plain 、 text/html 、 Files 。

说明
text/plain 普通字符串
text/html 带有样式的html
Files 文件(例如剪切板中的数据)

有了上面这些方法,我们可以解决第二个问题即获取到剪切板上的数据。

document.addEventListener('paste', function (e) {
   
    console.info(e
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值