- ;
- 计时API;
- Streams API;
- Encoding;
- File;Blob;
- 跨文档消息传输;
- 拖放;
- 历史状态管理
书摘&心得
跨文档消息传送(cross-document messaging)
有时候简称为 XDM,指的是在来自不同域的页面间传递消息。
- 例如,www.wrox.com 域中的页面与位于一个内嵌框架中的 p2p.wrox.com 域中的页面通信。
- 所有支持 XDM 的浏览器也支持 iframe 的 contentWindow 属性
核心是 postMessage()方法
- 参数1:一条消息。
- 最好只传字符串,不是所有浏览器都支持其他数据格式。
- 参数2:一个表示消息接收方来自哪个域的字符串。
- 对保障安全通信非常重要,可以防止浏览器把消息发送到不安全的地方
- 是”*”,则表示可以把消息发送给来自任何域的文档
var iframeWindow = document.getElementById("myframe").contentWindow; iframeWindow.postMessage("A secret", "http://www.wrox.com");
接收数据
// EventUtil为跨浏览器事件处理程序,详见第十三章 事件 EventUtil.addHandler(window, "message", function(event){ //确保发送消息的域是已知的域 if (event.origin == "http://www.wrox.com"){ //处理接收到的数据 processMessage(event.data); //可选:向来源窗口发送回执 event.source.postMessage("Received!", "http://p2p.wrox.com"); } });
原生拖放
说到拖放,最有意思的恐怕就是能够在框架间、窗口间,甚至在应用间拖放网页元素了
- 当某个元素被拖动到一个有效的放置目标上时,下列事件会依次发生:(1)dragenter (2)dragover (3)dragleave 或 drop
dataTransfer对象
- 在拖放间交互数据
- setData()
- 第一个参数:text、URL、各种MIME类型
getData()
- 唯一的参数,类型同上。
//设置和接收文本数据 event.dataTransfer.setData("text", "some text"); var text = event.dataTransfer.getData("text"); //设置和接收 URL event.dataTransfer.setData("URL", "http://www.wrox.com/"); var url = event.dataTransfer.getData("URL");
- 唯一的参数,类型同上。
dropEffect属性【484】
- 被拖动的元素能够执行哪种放置行为
- 只有搭配 effectAllowed 属性才有用
- effectAllowed 属性【484】
- 表示允许拖动元素的哪种 dropEffect
- 必须在 ondragstart 事件处理程序中设置 effectAllowed 属性
- 其他成员【485】
媒体元素
- 指定媒体来源
- 单个媒体:在标签中指定src属性
- 多个媒体:使用一或多个
元素
历史状态管理
在不加载新页面的情况下改变浏览器的 URL。
- history.pushState()方法创建新的历史记录。
history.replaceState()方法更新当前状态。
第四版新增
1 Atomics与SharedArrayBuffer
和缓冲区相关的API
2 Encoding API
主要用于实现字符串与定型数组之间的转换
- 可以将特殊字符存储为定型数组
- 看来定型数组虽然在webGL中使用,但其应用不仅限于webGL
- 在与后端约定某些特殊字符时,可以采用这种模式
- 编码:
3 File API与Blob API
让Web开发者能以安全的方式访问客户端机器上的文件
- File对象
- ❑ name:本地系统中的文件名。
- ❑ size:以字节计的文件大小。
- ❑ type:包含文件MIME类型的字符串。
- ❑ lastModifiedDate:表示文件最后修改时间的字符串(仅Chrome实现)
- FileReader类型
- 表示一种异步文件读取机制
- FileReaderSync类型就是FileReader的同步版本
- 拥有与FileReader相同的方法
- 只有在整个文件都加载到内存之后才会继续执行
- Blob登场:需要读取部分文件而不是整个文件
- File对象提供了一个名为slice()的方法。
- slice()方法接收两个参数:起始字节和要读取的字节数。
- 这个方法返回一个Blob的实例
- blob表示二进制大对象(binary larget object),是JavaScript对不可修改二进制数据的封装类型。
- Blob对象
- Blob实际上是File的超类(父类)
- 有一个size属性和一个type属性
- 还有一个slice()方法用于进一步切分数据。
- 另外也可以使用FileReader从Blob中读取数据。
对象URL有时候也称作Blob URL,是指引用存储在File或Blob中数据的URL
4 Notifications API
用于向用户显示通知。
5 Page Visibility
一个常见的问题是开发者不知道用户什么时候真正在使用页面
三大组成
和数据传输相关
- Web应用如何消费有序的小信息块而不是大块信息?
- 直接解决的问题是处理网络请求和读写磁盘。
- 定义了3种流:可读流、可写流、转换流
- 流的基本单位是块(chunk)。
- 块可是任意数据类型,但通常是定型数组。
- 块不是固定大小的,也不一定按固定间隔到达。
流不平衡
https://github.com/hijiangtao/javascript-articles-monthly月刊提到了Streams API
可读流
生成器的值可以通过可读流的控制器传入可读流
- new ReadableStream可以构造一个可读流的控制器
调用控制器的enqueue()方法可以把值传入控制器。
async function * ints() { // 每1000毫秒生成一个递增的整数 for(let i = 0; i < 5; ++i) { yield await new Promise((resolve) => setTimeout(resolve, 1000))); } } const readableStream = new ReadableStream({ async start(controller) { for await(let chunk of ints()) { controller.enqueue(chunk); } controller.close(); } });
将值从可读流中读取出来:
该实例可以通过流的getReader()方法获取。
- 调用这个方法会获得流的锁,保证只有这个读取器可以从流中读取值
消费者使用这个读取器实例的read()方法可以读出值: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); } } })(); // 0 // 1 // 2 // 3 // 4
可写流
```javascript const writableStream = new WritableStream({ write(value) { console.log(value); } });console.log(writableStream.locked); // false const writableStreamDefaultWriter = writableStream.getWriter(); console.log(writableStream.locked); //true
// 生产者 (async function() { for await (let chunk of ints()) { await writableStreamDefaultWriter.ready; writableStreamDefaultWriter.write(chunk); } writableStreamDefaultWriter.close(); })();
<a name="lqS9M"></a> #### 转换流 用于组合可读流和可写流: ```javascript const { writable, readable } = new TransformStream({ transform(chunk, controller) { controller.enqueue(chunk * 2); } }); const readableStreamDefaultReader = readable.getReader(); const writableStreamDefaultWriter = writable.getWriter();
通过管道连接流
- 流可以通过管道连接成一串。
使用pipeThrough()方法把ReadableStream接入TransformStream。
// 创建可读流 const intergerStream = new ReadableStream({ async start(controller) { for await(let chunk of ints()) { controller.enqueue(chunk); } controller.close(); } }); // 创建转换流 const doubleingStream = new TransformStream({ transform(chunk, controller) { controller.enqueue(chunk*2); } }); // 通过管道流连接 const pipedStream = integerStream.pipeThrough(doublingStream); // 从连接流的输出获得读取器 const pipedStreamDefaultReader = pipedStream.getReader(); // 然后将读取器给消费者使用 // ...
使用pipeTo()方法也可以将ReadableStream连接到WritableStream
const writableStream = new WritableStream({ write(value) { console.log(value); } }); // 隐式从ReadableStream获得了一个读取器,并把产生的值填充到WritableStream const pipedStream = integerStream.pipeTo(writableStream); // 0 // 1 // 2 // 3 // 4
7 计时API
Performance接口通过JavaScript API暴露了浏览器内部的度量指标
-
High Resolution Time API
定义了window.performance.now(),这个方法返回一个微秒精度的浮点值。
- Date.now()不够精确
performance.timeOrigin属性返回计时器初始化时全局系统时钟的值
User Timing API
在一个执行上下文中被记录的所有性能条目可以通过performance. getEntries()获取
PerformanceMark
用于度量当前页面加载速度
- 由performance.getEntriesByType(‘navigation’)获得性能数据对象obj
- 内含大量时间数据,如连接速度、dom加载速度等
最终时间计算:obj.responseEnd-obj.responseStart
Resource Timing API
用于度量当前页面加载时请求资源的速度
- 由performance.getEntriesByType(‘resource’)[0]获得性能数据对象obj
-
8 web组件
HTML模板(template)
基于HTML解析构建DOM子树,然后在需要时再把这个子树渲染出来。
- 什么是template
- 在浏览器中渲染时,上面例子中的文本不会被渲染到页面上。
- document.querySelector()等DOM查询方法不会发现其中的
标签
- 通过元素的content属性可以取得这个DocumentFragment的引用
- 然后就可以像操作document一样操作DocumentFragment的引用
- 使用DocumentFragment可以一次性添加所有子节点,最多只会有一次布局重排(性能不差)
复制模板,可以使用importNode()方法克隆DocumentFragment
fooElement.appendChild(document.importNode(barFragment, true);
脚本执行可以推迟到将DocumentFragment的内容实际添加到DOM树。
影子DOM
Shadow DOM:主要目的是使CSS与主文档的DOM保持分离
- 有CSS Module的情况下感觉没有必要
- 可以将一个完整的DOM树作为节点添加到父DOM树
- 尝试给无效元素或者已经有了影子DOM的元素添加影子DOM会抛错
影子DOM是通过attachShadow()方法创建并添加
const openShadowDom = foo.attachShadow({mode: 'open'}); // openShadowDom.shadowRoot #shadow-root(open) const closedShadowDom = bar.attachShadow({mode:'closed'}); // closedShadowDom.shadowRoot null
标签会将影子宿主的InnerHTM添加到影子DOM的槽位中 自定义元素
如何通过原生JS写像javascript框架一样的代码
- 内容过于平sang易xin近bing人kuang,详见书本