二十、Javascript API(一)

二十、Javascript API(一)_第1张图片

1. Atomics和SharedArrayBuffer

多个上下文访问 SharedArrayBuffer时,如果同时对缓冲区执行操作,就可能出现资源争用问题。Atomics API 通过强制同一时刻只能对缓冲区执行一个操作,可以让多个上下文安全地读写一个SharedArrayBuffer

1.1 SharedArrayBuffer

SharedArrayBufferArrayBuffer具有相同的API,其区别为,前者可以被任意多个执行上下文同时使用,后者必须在不同的执行上下文中进行切换

1.2原子操作基础

任何全局上下文中都有 Atomics 对象,这个对象上暴露了用于执行线程安全操作的一套静态方法,其中多数方法以一个 TypedArray 实例(一个 SharedArrayBuffer 的引用)作为第一个参数,以相关操作数作为后续参数。

算术与位操作方法

AtomicReadModifyWrite 操作。在底层,这些方法都会从 SharedArrayBuffer 中某个位置读取值,然后执行算术或位操作,最后再把计算结果写回相同的位置。这些操作的原子本质意味着上述读取、修改、写回操作会按照顺序执行,不会被其他线程中断。
Atomics.add()
Atomics.sub()
Atomics.or()
Atomics.and()
``Atomi

// 创建大小为 1 的缓冲区
let sharedArrayBuffer = new SharedArrayBuffer(1);
// 基于缓冲创建 Uint8Array
let typedArray = new Uint8Array(sharedArrayBuffer);
// 所有 ArrayBuffer 全部初始化为 0
console.log(typedArray); // Uint8Array[0]
const index = 0;
const increment = 5;
// 对索引 0 处的值执行原子加 5
Atomics.add(typedArray, index, increment);
console.log(typedArray); // Uint8Array[5]
// 对索引 0 处的值执行原子减 5
Atomics.sub(typedArray, index, increment);
console.log(typedArray); // Uint8Array[0]
原子读与写

浏览器的 JavaScript 编译器和 CPU 架构本身都有权限重排指令以提升程序执行效率,但多线程下的指令重排可能导致资源争用。
Atmoics API通过两种主要的方式解决该问题

  • 所有原子指令之间的顺序永远不会重排
  • 使用原子读或者原子保证所有指令都不会相对原子读/写重排
    Atomics.load()Atomics.store()还可以构建“代码围栏”。JavaScript引擎保证非原子指令可以相对于 load()或 store()本地重排,但这个重排不会侵犯原子读/写的边界。
原子交换

Atomics.exchange()执行简单的交换,以保证其他线程不会中断值的交换

const sharedArrayBuffer = new SharedArrayBuffer(4);
const view = new Uint32Array(sharedArrayBuffer);
// 在索引 0 处写入 3
Atomics.store(view, 0, 3);
// 从索引 0 处读取值,然后在索引 0 处写入 4
console.log(Atomics.exchange(view, 0, 4)); // 3
// 从索引 0 处读取值
console.log(Atomics.load(view, 0)); // 4

compareExchange()方法只在目标索引处的值与预期值匹配时才会执行写操作
如果值不匹配,compareExchange()调用则什么也不做.

const sharedArrayBuffer = new SharedArrayBuffer(4);
const view = new Uint32Array(sharedArrayBuffer);
// 在索引 0 处写入 5
Atomics.store(view, 0, 5);
// 从缓冲区读取值
let initial = Atomics.load(view, 0);
// 对这个值执行非原子操作
let result = initial ** 2;
// 只在缓冲区未被修改的情况下才会向缓冲区写入新值
Atomics.compareExchange(view, 0, initial, result);
// 检查写入成功
console.log(Atomics.load(view, 0)); // 25
const sharedArrayBuffer = new SharedArrayBuffer(4);
const view = new Uint32Array(sharedArrayBuffer);
// 在索引 0 处写入 5
Atomics.store(view, 0, 5);
// 从缓冲区读取值
let initial = Atomics.load(view, 0);
// 对这个值执行非原子操作
let result = initial ** 2;
// 只在缓冲区未被修改的情况下才会向缓冲区写入新值
Atomics.compareExchange(view, 0, -1, result);
// 检查写入失败
console.log(Atomics.load(view, 0)); // 5
原子Futex操作和锁

Atomics.wait(view, index, targetVal, time), 当索引index位置对应的值等于targetVal时,等待以获取锁,超时时间为time,超时顶部执行上下文会调用Atomics.notify()释放其中一个等待的线程。
Atmoics.notify(view, index, count), 允许count个线程继续在index操作。
Atomics.isLockFree()方法在高性能算法中可以用来确定是否有必要获取锁。

2.跨消息上下文

postMessage()方法接收 3 个参数:消息、表示目标接收源的字符串和可选的可传输对象的数组(只与工作线程相关)
onmessage的相应事件对象event包含三个方面的信息

  • data, postMessage()的第一个参数
  • origin, 发送消息的文档源
  • source, 发送消息的文档中window对象的代理

3. Encoding API

Encoding API 主要用于实现字符串与定型数组之间的转换。规范新增了 4 个用于执行转换的全局类:TextEncoderTextEncoderStreamTextDecoderTextDecoderStream

3.1 文本编码

Encoding API 提供了两种将字符串转换为定型数组二进制格式的方法:批量编码流编码。把字符串转换为定型数组时,编码器始终使用 UTF-8.
批量编码使用TextEncoder的实例

  • encode(),接受一个字符串参数,并以Uint8Array格式返回每个字符的UTF-8编码
  • encodeInto(),第一个参数为字符串str,第二个参数为目标Uint8Array,将str写入目标Uint8Array,返回一个字典,该字典包含readwritten两个属性,分别表示成功读取和写入的字符。

流编码使用TextEncoderStream的实例

3.2 文本解码

批量解码-----TextDecoder

  • decode(), 不关心传入的是哪种定型数组,与 TextEncoder 不同,TextDecoder 可以兼容很多字符编码。

流解码-----TextDecoderStream

4. File API 与Blob API

4.1 File类型

File API 仍然以表单中的文件输入字段为基础,但是增加了直接访问文件信息的能力。每个File对象包含以下只读属性

  • name, 本地系统中的文件名
  • size, 以字节计算的文件大小
  • type, 包含文件MIME类型的字符串
  • lastModifiedDate,文件最后修改的时间字符串,仅仅Chrome有

4.2 FileReader类型

异步读取文件,具有以下的方法

  • readAsText(file, encoding), 从文件中读取纯文本内容,并保存在result属性中
  • readAsDataURL(file),读取文件并将内容的数据URL保存在result属性中
  • readAsBinaryString(file), 读取文件并将每个字符的二进制数据保存在result属性中
  • readAsArrayBuffer(file), 读取文件,并将内容以ArrayBuffer形式保存在result属性中

支持的事件处理程序

  • progress, 表示还有更多数据,约没50毫秒触发一次,包含lengthComputableloadedtotal等信息,还可以通过result属性读取已经读到的数据。
  • error, 发生错误,只包含一个信息code。这个错误码的值可能是
    • 1(未找到文件)
    • 2(安全错误)
    • 3(读取被中断)
    • 4(文件不可读)
    • 5(编码错误)
  • load, 读取完成

4.3 FileReaderSync 类型

FileReaderSync 类型就是 FileReader 的同步版本。这个类型拥有与 FileReader
相同的方法,只有在整个文件都加载到内存之后才会继续执行。FileReaderSync 只在工作线程中可用,因为如果读取整个文件耗时太长则会影响全局。

// worker.js
self.omessage = (messageEvent) => {
	 const syncReader = new FileReaderSync();
	 console.log(syncReader); // FileReaderSync {}
	 // 读取文件时阻塞工作线程
	 const result = syncReader.readAsDataUrl(messageEvent.data);
	 // PDF 文件的示例响应
	 console.log(result); // data:application/pdf;base64,JVBERi0xLjQK...
	 // 把 URL 发回去
	 self.postMessage(result);
}; 

4.4 Blob与部分读取

读取部分文件,File对象具有slice(startByteIndex, endByteIndex)方法,返回一个Blob实例。BlobFile的超类

blob 表示二进制大对象(binary larget object),是 JavaScript 对不可修改二进制数据的封装类型。包含字符串的数组、ArrayBuffers、ArrayBufferViews,甚至其他 Blob 都可以用来创建 blob。Blob构造函数可以接收一个 options 参数,并在其中指定 MIME 类型.

Blob 对象有一个 size 属性和一个 type 属性,还有一个 slice()方法用于进一步切分数据,也可以使用 FileReader 从 Blob 中读取数据。

4.5 对象URL和Blob

创建对象URL,使用 window.URL.createObjectURL()方法并传入 File 或 Blob 对象。
释放对象URL, 使用window.URL.revokeObjectURL(url)

4.6 读取拖放文件

在页面创建放置目标后,被放置的文件可以通过事件的 event.dataTransfer.files 属性读到,这个属性保存着一组 File 对象。
必须取消 dragenterdragoverdrop的默认行为

5.媒体元素

视频和音频的处理分别使用\\,主要属性有src/width/height/poster/\.

5.1 属性

属性 数据类型 说明
autoplay boolean 取得或者设置autoplay标签,下载完自动开始播放
buffered TimeRanges 表示已经下载缓冲的时间范围
bufferedBytes ByteRanges 表示已经下载缓冲的字节范围
bufferingRate integer 平均每秒下载的位数
bufferingThrottled boolean 表示缓冲是否有被浏览器截流
controls boolean 取得或设置controls属性,用于显示或者隐藏控件
currentLoop integer 已经循环播放的次数
currentSrc string 播放媒体的url
currentTime float 已经播放的秒数
defaultPlaybackRate float 默认回放速率,默认1.0秒
duration float 总秒数
ended booelan 是否播放完
loop boolean 是否循环播放
muted boolean 是否静音
networkState integer 当前网络连接状态,0空,1加载中,2加载元数据,3加载了第一帧,4加载完成
paused boolean 是否暂停
playbackRate float 设置播放速率
played TimeRanges 已经播放的时间范围
readyState integer 是否已经准备就绪,0媒体不可用,1可以显示当前帧,2可以开始播放,3可以从头播放到尾
seekable TimeRanges 可以跳转的时间范围
seeking boolean 是否正移动到媒体的新位置
src string 媒体资源url,随时可以改写
start float 取得或者设置媒体文件中的位置,以秒为单位,从该处开始播放
totalBytes integer 总大小
videoHeight/videoWidth integer
volume float 当前音量值,0.0-1.0

5.2事件

事件 何时触发
abort 下载被中断
canplay 可以开始回放,readyState === 2
canplaythrough 回放可以继续,readyState === 3
canshowcurrentframe 已经下载当前帧,readyState === 1
dataunavailable 不能回放,readyState=== 0
durationchange duration属性发生变化
emptied 网络连接关闭
empty 发生了错误,组织媒体下载
ended 媒体已经播放完一遍,并且停止了
error 下载期间发生网络错误
loadeddata 第一帧已经下载
loadedmetadata 元数据已经下载
loadstart 下载已经开始
pause 回放已经暂停
paly 媒体收到开始播放的请求
playing 媒体已经开始播放
progress 下载中
ratechange 播放速率发生变化
seeked 跳转已经结束
seeking 回放已经移动到新的位置
stalled 浏览器尝试下载,但是尚未收到数据
timeupdate currentTime被非常规或者意外地修改了
volumechange volume或者muted属性被修改
waiting 回放暂停,以下载更多的数据

5.3检测编解码器

const audio = document.getElementById('audio-player');
if (audio.canPlayType("audio/mpeg"){
	//...
}
if (audio.canPlayType("audio/ogg;codecs=\"vorbis\"")){
	//...
}

5.4 音频类型

Audio构造函数,与Image类似,但是不需要插入文档即可工作

let audio = new Audio("sound.mp3");
EventUtil.addHandler(audio, "canplaythrough", function(event){
	audio.play();
});

6. 原生拖放

6.1拖放事件

被拖放元素的身上会依次触发dragstart/drag/dragend
目标元素身上会依次触发dragenter/dragover/dragleave或者drop

6.2 自定义拖放目标

如果把元素拖动到不允许放置的目标上,无论用户动作是什么都不会触发 drop 事件。不过,通过event.preventDefault()覆盖dragenter dragover 事件的默认行为,可以把任何元素转换为有效的放置目标。

let droptarget = document.getElementById("droptarget");
droptarget.addEventListener("dragover", (event) => {
 	event.preventDefault();
 	//...
});
droptarget.addEventListener("dragenter", (event) => {
 	event.preventDefault();
 	//...
});

6.3 DataTransfer对象

dataTransfer 对象,用于从被拖动元素向放置目标传递字符串数据。因为这个对象是event 的属性,所以在拖放事件的事件处理程序外部无法访问 dataTransfer
dataTransfer 对象有两个主要方法:getData() setData()。顾名思义,getData()用于获取 setData()存储的值。setData()的第一个参数以及 getData()的唯一参数是一个字符串

6.4 dropEffect 和 effectAllowed

dataTransfer 对象不仅可以用于实现简单的数据传输,还可以用于确定能够对被拖动元素和放置目标执行什么操作。为此,可以使用两个属性:dropEffecteffectAllowed
dropEffect 属性可以告诉浏览器允许哪种放置行为,有以下 4 种可能的值:

  • none, 被拖动元素不能放到这里。这是除文本框之外所有元素的默认值。
  • move, 被拖动元素应该移动到放置目标。
  • copy,被拖动元素应该复制到放置目标。
  • link, 表示放置目标会导航到被拖动元素(仅在它是 URL 的情况下)。

为了使用 dropEffect 属性,必须在放置目标的 ondragenter 事件处理程序中设置它,并且同时设置 effectAllowed,否则 dropEffect 属性也没有用
effectAllowed 属性表示对被拖动元素是否允许 dropEffect,有如下几个可能的值:

  • uninitialized, 没有给被拖动元素设置动作。
  • none, 被拖动元素上没有允许的操作。
  • copy, 只允许"copy"这种 dropEffect。
  • link, 只允许"link"这种 dropEffect。
  • move, 只允许"move"这种 dropEffect。
  • copyLink, 允许"copy"和"link"两种 dropEffect。
  • copyMove, 允许"copy"和"move"两种 dropEffect。
  • linkMove, 允许"link"和"move"两种 dropEffect。
  • all, 允许所有 dropEffect。
    必须在 ondragstart 事件处理程序中设置这个属性

6.5 可拖动能力

draggable 属性,表示元素是否可以拖动。图片和链接的 draggable 属性自动被设置为 true,而其他所有元素此属性的默认值为 false

6.6 其他成员

HTML5 规范还为 dataTransfer 对象定义了下列方法:

  • addElement(element):为拖动操作添加元素。
  • clearData(format):清除以特定格式存储的数据。
  • setDragImage(element, x, y):允许指定拖动发生时显示在光标下面的图片。
  • types:当前存储的数据类型列表。

你可能感兴趣的:(AtomicsAPI,Encoding,File,and,Blob,video,audio,drag)