js红宝石 第二十章-JavaScript API

这章介绍的API是被多个浏览器支持且其他章节没有提到的

20.1 Atomics 和 SharedArrayBuffer

多个上下文访问SharedArrayBuffer时,如果同时对缓冲区执行操作,可能会出现资源争用

Atomics API的设计初衷时在最少但是稳定的原子行为基础之上,构建复杂的多线程JavaScript程序

20.1.1 SharedArrayBuffer

sharedArrayBuffer 和ArrayBuffer 具有相同的API

ArrayBuffer必须在不同的上下文之间切换,但是SharedArrayBuffer可以被任意多个上下文同时使用

20.1.2 原子操作基础

任何全局上下文中都有Atomics对象,这个对象暴露了用于执行线程安全操作的一系列静态方法,这些方法的第一个参数一般都是TypeArray(SharedArrayBuffer)的引用

1.算数以及位操作方法

    // 创建大小为1的缓冲区
    let sharedArrayBuffer = new SharedArrayBuffer(1)

    // 基于缓冲区创建Unit8Array
    let typeArray = new Uint8Array(sharedArrayBuffer)

    // 所有ArrayBuffer 全部初始化为0
    console.log(typeArray)// Uint8Array[0]

    const index = 0;
    const increment = 5;

    // 对0处的位置+5
    Atomics.add(typeArray,index,increment)
    console.log(typeArray)// Uint8Array[5]

    // 对0处的位置-5
    Atomics.sub(typeArray,index,increment)
    console.log(typeArray)// Uint8Array[0]

or 或

and 与

xor 异或

2.原子的读和写

所有原子指令相互之间的顺序永远不会重排

使用原子读或原子写保证所有指令都不会相对原子读/写重新排序

Atomics.load() 和 Atomics.store()还可以构建代码围栏,保证非原子指令相对于load() 或 store() 本地重排

3.原子交换

使用exchange() 和 compareExchange()

4.原子Futex操作和加锁

Atomics API 提供了模仿Linux Futex 快速用户控件互斥量的方法,可以作为复杂锁组件的基本组件

Atomics.wait() 和 Atomics.notify()

20.2 跨上下文消息

跨文档消息(XDM) 是一种在不同执行上下文减传递信息的能力

XDM的核心是postMessage()

接受三个参数: 消息,目标接受源的字符串,可选的传输对象的组织

    let iframeWindow = document.getElementById('myFrame').contentWindow
    iframeWindow.postMessage("A MSG","http://www.wrox.com")

接到XDM消息后,window对象会触发message事件

message事件上的event对象包含三个重要信息:

data: 消息

origin: 发送消息的原文档

source: 发送消息的文档中window对象的代理

20.3 Encoding API

Encoding API主要实现字符串与定型数组之间的转换

20.3.1 文本编码

Encoding API通过批量编码和流编码把字符串转换位定型数组,编码器始终使用UTF-8

1.批量编码

JS会同步编码整个字符串

通过TextEncoder的实例完成:

    const textEncoder = new TextEncoder()
    const decodeText = 'foo'
    const encodeText = textEncoder.encode(decodeText)

    console.log(encodeText);

2.流编码

TextEncoderStream就是TransformStream形式的TextEncoder

20.3.2 文本解码

Encoding API通过批量解码和流解码把定型数组转换为字符串

编码器默认使用UTF-8

1.批量解码

通过TextDecoder实例完成


      const textDecoder = new TextDecoder()

      const encodedText = Uint8Array.of(102, 111, 111)
      const decodedText = textDecoder.decode(encodedText)

      console.log(decodedText) // foo

2.流解码

TextDecoderStream就是TransformStream形式的TexDecoder

文本解码器流经常和fetch()一起使用,因为响应体可以通作为ReadableStream来处理

20.4 File API 和 Blob API

20.4.1 File

File API以表单中的文件输入字段为基础,但是增加了直接访问文件信息的能力

H5在DOM上为文件输入元素添加了files集合

files集合会包含一组File对象,每个File对象都只有一些只读属性

name: 本地系统中的文件名

size: 文件大小

type: MIME类型的字符串

lastModifiedDate: 文件最后修改时间

20.4.2 FileReader

readAsText(file,encoding) 读取文件纯文本

readAsDataURL(file) 读取URI

readAsBinaryString(file) 读取二进制数据

readAsArrayBuffer(file) 读取为ArrayBuffer

20.4.3 FileReaderSync

FileReaderSync就是FileReader的同步版本

FileReaderSync只在工作线程中可用

20.4.4 Blob与部分读取

slice()方法读取部分文件,返回一个Blob的实例,而Blob实际上是File的超类

blob表示二进制大对象

20.4.5 对象URL和Blob

对象URL是用来引用储存在File或Blob中数据的URL

对象URL不需要把对象读取到JS也可以使用文件

使用window.URL.createObjectURL(),传入File或Blob,返回一个指向内存中地址的字符串

20.4.6 读取拖放文件

组合使用H5的 拖放API 和 File API,可用从桌面上把文件拖动并放置到相应位置

这样做会触发drop事件

20.5 媒体元素

<video>嵌入视频

<audio>嵌入音频

20.5.1 属性

autoplay 自动播放

loop 循环播放

... p628

20.5.2 事件

abort 下载中断

pause 暂停

play 播放

... p629

20.5.3 自定义媒体播放器

实现简单的媒体播放器

  <body>
    <div class="mediaplayer">
      <div class="video">
        <video id="player" src="movie.mov" poster="mymovie.jpg" width="300" height="200">
          Video player no available
        </video>
      </div>
      <div class="controls">
        <input type="button" value="Play" id="video-btn">
        <span id="curtime">0</span> <span id="duration">0</span>
      </div>
    </div>
    <script>
      let player = document.getElementById('player'),
        btn = document.getElementById('video-btn'),
        curtime = document.getElementById('curtime'),
        duration = document.getElementById('duration')
      duration.innerHTML = player.duration

      btn.addEventListener("click",(e)=>{
        if(player.paused){
          player.play()
          btn.value = "Pause"
        } else {
          player.pause()
          btn.value = "Play"
        }
      })

      setInterval(()=>{
        curtime.innerHTML = player.currentTime
      },250)

    </script>
  </body>

20.5.4 检测解编码器

在视频元素上使用canPlaytype()检测视频格式

20.5.4 音频类型

要使用Audio播放音频,只需要创建一个Audio的实例并传入音频源文件

创建实例的时候会开始下载,下载完后可用通过play()播放

20.6 原生拖放

现在几乎所有元素都可以拖放

20.6.1 拖放事件

在拖放时,会按顺序触发下面的事件:

dragstart

drag

dragend

把元素拖动到有效的防止目标上时,会依次触发以下事件:

dragenter

dragover

dragleave或drop

20.6.2 自定义放置目标

覆盖dragover和dragenter事件,可用吧任何元素都转化为有效的放置目标

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

20.6.3 dataTransfer对象

事件处理对象event上暴露了dataTransfer对象,用来从被拖动元素向防止目标传递字符串数据

dataTransfer对象有两个方法: getData() 和 setData()

20.6.4 dropEffect 和 effectAllowed

dataTransfer对象不仅可以实现简单的数据传输,还可以用于确定能够对被拖动元素和放置目标执行什么操作

可以使用 dropEffect 和 effectAllowed

dropEffect可以告诉浏览器允许那种放置行为:

none: 不能放到这里

move: 应该移动到放置目标

copy:  应该复制到放置目标

link: 放置目标会导航到被拖动元素

除非同时设置effectAllowed,否则dropEffect属性也没有用

20.6.5 可拖动能力

H5在所有HTML元素上设置了draggable属性,表示元素是否可以拖动

20.6.6 其他成员

H5还为dataTransfer对象定义了如下方法:

addElement(element): 为拖动操作添加元素

clearData(format): 清除以特定格式存储的数据

setDragImage(element,x,y): 允许指定拖动发生时显示在光标下面的图片

20.7 Notifications API

Notifications API用于向用户显示通知,类似alert()的对话框

20.7.1 通知权限

Notifications API默认会开启亮相安全措施:

通知只能在运行安全上下文代码时被触发

通知必须按照每个源的原则明确得到用户允许
 

20.7.2 显示和隐藏通知

Notification构造函数用于创建和显示通知

可以通过options参数对通知自定义

      new Notification("Title text",{
        body: 'body text',
        image: 'url',
        vibrate: true
      })

20.7.3 通知生命周期回调

Notification提供了四个用于添加回调的生命周期方法

onshow 在通知显示时触发

onclick 在通知被点击时触发

onclose 在通知消失或被close()关闭时触发

onerror 在通知发生错误时触发

20.8 Page Visibility API

Page Visibility API为开发者提供页面是否可见的信息

组成部分:

document.visibilityState,表示:

页面被最小化了 hidden

页面在前台 visible

页面被隐藏了 prerender

visibilitychange: 可见状态变化时触发

document.hidden: 表示页面是否隐藏

2.9 Streams API

流:大块数据可以分成小部分处理

20.9.1 理解流

Stream定义了三种流:

可读流: 可以通过某个数据接口读取数据块的流,由消费者处理

可写流: 可以通过某个数据接口写入数据块的流,由生产者写入

转换流: 由上面两种流组成,这两个流之间是转换程序

流的基本单位是块

如果入列速度大于出列速度,会使用反压通知流入口停止发送,直到降低到某个阈值之下,这个阈值叫高水位线

20.9.2 可读流

ReadableStreamDefaultController

      const readableStream = new ReadableStream({
        start(controller){
          console.log(controller); //ReadableStreamDefaultController
        }
      })

调用控制器的enqueue() 方法可以把值传入控制器

传完值后使用close()关闭流

      async function * ints(){
        for(let i=0;i<5;i++){
          yield await new Promise((resolve)=>setTimeout(resolve,1000,i))
        }
      }

      const readableStream = new ReadableStream({
        async start(controller){
          for await(let chunk of ints()){
            controller.enqueue(chunk)
          }
        controller.close()
        }
      })

ReadableStreamDefaultReader

该实例可以通过流的getReader()方法获取,调用这个方法会获得流的锁,保证只有这个读取器可以从流中读取值

      async function * ints(){
        for(let i=0;i<5;i++){
          yield await new Promise((resolve)=>setTimeout(resolve,1000,i))
        }
      }

      const readableStream = new ReadableStream({
        async start(controller){
          for await(let chunk of ints()){
            controller.enqueue(chunk)
          }
        controller.close()
        }
      })

      console.log(readableStream.locked);// false
      const readableStreamDefaultReader = readableStream.getReader()
      console.log(readableStream.locked);// true

使用read()方法可以读出值

    <div draggable="true">123</div>
    <script>
      async function* ints() {
        for (let i = 0; i < 5; i++) {
          yield await new Promise((resolve) => setTimeout(resolve, 1000, i))
        }
      }

      const readableStream = new ReadableStream({
        async start(controller) {
          for await (let chunk of ints()) {
            controller.enqueue(chunk)
          }
          controller.close()
        },
      })

      console.log(readableStream.locked) // false
      const readableStreamDefaultReader = readableStream.getReader()
      console.log(readableStream.locked) // true

      // 消费者
      (async function () {
        while (true) {
          const { done, value } = await readableStreamDefaultReader.read()
          if (done) {
            break
          } else {
            console.log(value)
          }
        }
      })()

20.9.3  可写流

20.9.4  转换流

20.9.5  管道连接流

要用再看把

20.10 计时API

Performance接口暴露了浏览器内部的度量指标

Performance接口API:


High Resolution Time APIperformance.now() 采用相对度量

Performance Timeline API

navigationTiming API

User Timing API

Resource Timing API

Paint Timing API

20.11 Web组件

这里的Web组件是一套用来增强DOM行为的工具

20.11.1 HTML模板

提前在页面中写出特殊标记,让浏览器自动将其解析为DOM子树

使用<template>模板

    <template id="foo">
      <p>I'm inside</p>
    </template>

1.DocumentFragment

上面的例子不会被渲染到页面上,因为<template>内容不属于活动文档

 使用content可以取得DocumentFragment的引用

    let fragment = document.querySelector("#foo").content

可以使用fragment来添加新元素

使用importNode()复制DocumentFragment到div上

脚本执行可以推迟DocumentFragment的内容实际添加到DOM树

20.11.2 影子DOM

可以通过影子DOM把一棵完整的DOM树添加到父DOM树

影子DOM是通过attachShadow()创建并添加给有效HTML元素的

有效HTML标签:p652

影子DOM必须包含一个mode属性,open可以通过shadowRoot获取,closed则不行

但是不能为了安全而创建影子DOM

影子DOM可以在DOM树之间无限制移动

要使用<slot>来指定在哪里放置原来的HTML

可以使用命名槽位来指定多个投射

在影子DOM中发生的事件会逃避并通过重定向在外部被处理

20.11.3 自定义元素

浏览器会尝试把无法识别的元素作为通用元素整合进DOM

自定义元素在此基础上更进一步,可以为其定义复杂的行为,也可以把它纳入生命周期管理

调用customElements.define()方法可以创建自定义元素

可以为自定义元素添加影子DOM并添加内容

自定义元素的生命周期方法:p660

要从JS对象反射到DOM元素,要使用获取和设置函数

可以使用CustomElementRegistry的额外方法升级自定义元素

20.12 Web Cryptography API

描述了一套密码学工具,规范了JS如何以安全和符合惯例的方式实现加密

Math.random()是伪随机数生成器

CSPRNG额外增加了一个熵作为输入,虽然速度变慢了,但是安全性得到了极大提高

可以通过crypto.getRandomValues()访问

Web Cryptography API的重要特性都包含在SubtleCrypto对象上

可以通过window.crypto.subtle访问

包含常用的密码学方法

SubtleCrypto对象使用CryptoKey类的实例生成密钥

SubtleCrypto.generateKey()随机生成CryptoKey

使用exportKey()并指定格式就可以取得密钥

和exportKey()相反的操作使用importKey()实现

deriveKey() 和 deriveBits() 可以通过已配置的属性从已有密钥获得新密钥

SubtleCrypto.sign() 和 SubtleCrypto.verify() 可以生成签名或者验证签名

SubtleCrypto.encrypt() 和 SubtleCrypto.decrypt() 加密/解密

SubtleCrypto.warpKey() 和 SubtleCrypto.unwarpKey() 包装/解包

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值