JavaScript API Atomics和SharedArrayBuffer SharedArrayBuffer SharedArrayBuffer与ArrayBuffer具有同样的API,但是ArrayBuffer必须在不同执行上下文间切换,而SharedArrayBuffer可以被任意多个执行上下文同时使用
原子操作基础 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 let sharedArrayBuffer = new SharedArrayBuffer (1 )let typedArray = new Unit8Array (sharedArrayBuffer)const index = 0 const increment = 5 Atomics .add (typedArray, index, increment)Atomics .sub (typedArray, index, increment)Atomics .load (view, 0 ) Atomics .store (view, 0 , 2 ) Atomics .exchange (view, 0 , 4 ) Atomics .compareExchange (view, 0 , initial, result) Atomics .wait (view, 0 , 0 , 1E4 ) Atomics .notify (view, 0 , 1 )
跨上下文消息 1 2 3 4 5 6 window .addEventListener ('message' , (event ) => { if (event.origin === 'xxx' ) { processMessage (event.data ) event.source .postMessage ('received!' , 'origin url' ) } })
Encoding API 实现字符串和定型数组之间的转换
文本编码 批量编码 1 2 3 4 5 6 7 const textEncoder = new TextEncoder ()const decodedText = 'foo' const encodedText = textEncoder.encode (decodedText) const fooArr = new Uint8Array (3 )const fooResult = textEncoder.encodeInto ('foo' , fooArr)console .log (fooResult)
流编码 文本解码 批量解码 1 2 3 4 const textDecoder = new TextDecoder ()const encodedText = Uint8Array .of (102 , 111 , 111 )const decodedText = textDecoder.decoder (encodedText)console .log (decodedText)
流解码 File API与Blob API File类型 1 2 3 4 5 6 7 8 9 10 11 let filesList = document .getElementById ('files-list' ) filesList.addEventListener ('change' , (event ) => { let files = event.target .files let i = 0 let len = files.length while (i < len) { const f = files[i] console .log (`${f.name} ${f.type} ${f.size} bytes` ) i++ } })
FileReader类型 一种异步读取文件机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 let filesList = document .getElementById ('files-list' ) filesList.addEventListener ('change' , (event ) => { let info = '' output = document .getElementById ('output' ) progress = document .getElementById ('progress' ) files = event.target .files type = 'default' reader = new FileReader () if (/image/ .test (files[0 ].type )) { reader.readAsDataURL (files[0 ]) type = 'image' } else { reader.readAsText (files[0 ]) type = 'text' } reader.onerror = function ( ) { output.innerHTML = 'Could not read file, error code is ' + reader.error .code } reader.onprogress = function ( ) { if (event.lengthComputable ) { progress.innerHTML = `${event.loaded} / ${event.total} ` } } reader.onload = function ( ) { let html = '*' switch (type) { case 'image' : html = `<img src="${reader.result} ">` break case 'text' : html = reader.result break } output.innerHTML = html } })
FileReaderSync类型 FileReader的同步版本,只有在整个文件都加载到内存后,才会继续执行。FileReaderSync只有在工作线程可用,因为如果读取整个文件太耗时则会影响全局
1 2 3 4 5 6 7 self.onmessage = (event ) => { const syncReader = new FileReaderSync () const result = syncReader.readAsDataURL (event.data ) console .log (result) self.postMessage (result) }
Blob与部分读取 1 2 3 4 5 6 7 8 9 10 11 12 function * slice (file ) { const MB = 1024 * 1024 let i = 0 let start = 0 while (true ) { const end = start + MB const blob = file.slice (start, end) if (blob.size () === 0 ) break yield { chunk : i++, blob } start = end } }
对象URL与Blob 1 2 3 4 5 6 7 8 9 10 let filesList = document .getElementById ('files-list' ) filesList.addEventListener ('change' , (event ) => { output = document .getElementById ('output' ) progress = document .getElementById ('progress' ) files = event.target .files url = window .URL .createObjectURL (files[0 ]) if (url) { output.innerHTML = `<img src="${url} ">` } }
只要对象URL还在使用,就不能释放内存,如果不再使用对象URL,则可以传给window.URL.revokeObjectURL()。
原生拖放 拖放事件 在某个元素被拖动时,会依次触发dragstart、drag和dragend
在按住鼠标不放并移动鼠标的那一刻,被拖动元素上会触发dragstart事件,dragstart事件触发后,只要目标还在拖动就会持续触发drag事件,当拖动停止时(把元素放到有效或无效的放置目标上),会触发dragend事件,3个事件的目标都是被拖动的元素
把元素拖动到一个有效的放置目标,会依次触发dragenter、dragover和(dragleave或drop)
只要把元素拖动到放置目标上,dragenter事件就会触发,dragenter事件触发之后,会立即触发dragover事件,并且在放置目标范围内拖动期间会持续触发。当元素被拖动到放置目标之外,dragover事件停止触发,dragleave事件触发,如果元素被拖动到了目标上,会触发drop事件,而不是dragleave事件
自定义放置目标 1 2 3 4 5 6 7 8 9 10 11 12 13 let droptarget = document .getElementById ('droptarget' ) droptarget.addEventListener ('dragover' , (e ) => { e.preventDefault () }) droptarget.addEventListener ('dragenter' , (e ) => { e.preventDefault () }) droptarget.addEventListener ('drag' , (e ) => { e.preventDefault () })
dataTransfer对象 所有拖动事件event都可以访问dataTransfer属性
1 2 event.dataTransfer .setData ('text' , 'test' )let text = event.dataTransfer .getData ('text' )
dropEffect与effectAllowed 必须在dragstart事件中设置这个属性
dropEffect
‘none’: 被拖动元素不能放到这里。除文本框之外所有元素的默认值
‘move’: 被拖动元素应该移动到放置目标
‘copy’: 被拖动元素应该复制到放置目标
‘link’: 表示放置目标会导航到被拖动元素
effectAllowed 表示被拖动元素是否允许dropEffect
可拖动能力 1 2 3 4 // 设置元素的draggable属性<div draggable ='true' > </div >
Notification API 通知权限 1 2 3 4 5 6 7 8 Notification .requestPermission ().then ((permission ) => { if (permission === 'granted' ) { } else { } })console .log (window .Notification .permission )
显示和隐藏通知 1 2 3 4 5 6 const n = new Notification ('title text' , { body : 'body text' , image : 'image.png' , vibrate : true })setTimeout (() => n.close (), 1000 )
通知声明周期回调 1 2 3 4 5 const n = new Notification ('foo' ) n.onshow = () => console .log ('notification was shown' ) n.onclick = () => console .log ('notification was clicked' ) n.onclose = () => console .log ('notification was closed' ) n.onerror = () => console .log ('notification experienced an error' )
Page Visibility API 1 2 3 document .addEventListener ('visibilitychange' , () => { console .log (document .visibilityState ) })
Streams API 计时API performance.now()计时器采用相对度量,在执行上下文创建时从0开始计时。例如,打开页面或创建工作线程时,performance.now()会从0开始计时
performance.timeOrigin属性返回计时器初始化时全局系统时钟的值
1 2 const relativeTimestamp = performance.now ()const absoluteTimestamp = performance.timeOrigin + relativeTimestamp
Web组件 影子DOM 基础使用 1 2 3 4 const div = document .createElement ('div' )const shadowDOM = div.attachShadow ({ mode : 'open' })document .body .appendChild (div) shadowDOM.innerHTML = '<p> test dom </p>'
影子DOM槽位 1 2 3 4 5 const div = document .createElement ('div' )const shadowDOM = div.attachShadow ({ mode : 'open' })document .body .appendChild (div) div.innerHTML = '<p>Foo</p><p slot="bar">Bar</p>' shadowDOM.innerHTML = '<div id="bar" > <slot></slot> <slot name="bar"></slot></div>'
自定义元素 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class FooElement extends HTMLDivElement { constructor ( ) { super () this .attachShadow ({ mode : 'open' }) this .shadowRoot .innerHTML = '<p>I am inside a custom element!</p>' } connectedCallback ( ) { } disconnectedCallback ( ) { } attributeChangedCallback ( ) { } adoptedCallback ( ) { } } customElements.define ('x-foo' , FooElement , { extends : 'div' })document .body .innerHTML = '<div is="x-foo"></div>'