一、Gamepad API
简介:
给予开发者一种简单、统一的方式来识别并响应游戏控制器(手柄)。其中包含了三个接口、两个事件、一个特殊函数,用来响应控制器的连接与断开、获取其他关于控制器的信息以及识别当前是哪个按键或是哪个控制器被按下了。GamepadButton
接口定义了在一个手柄或其他控制器的唯一的一个按键,允许访问不同控制器设备可用类型的按钮的当前状态。GamepadButton
对象是由 Gamepad
接口的 buttons
属性返回的可查询任意值的数组返回的。目前IE Edge版本支持,其他浏览器已经基本支持(移动端android webview不支持)
示例:
window.addEventListener("gamepadconnected", function(e) {
//当控制器连接时,执行
console.log("控制器已连接与 %d 位: %s. %d 个按钮, %d 个坐标方向。",
e.gamepad.index, e.gamepad.id,
e.gamepad.buttons.length, e.gamepad.axes.length);
});
window.addEventListener("gamepaddisconnected",function(e){
//断开连接时,执行
console.log("控制器已从 %d 位断开:%s",
e.gamepad.index, e.gamepad.id);
});
function gameLoop() {
if(navigator.webkitGetGamepads) {
var gp = navigator.webkitGetGamepads()[0];
if(gp.buttons[0] == 1) {
b--;
} else if(gp.buttons[1] == 1) {
a++;
} else if(gp.buttons[2] == 1) {
b++;
} else if(gp.buttons[3] == 1) {
a--;
}
} else {
var gp = navigator.getGamepads()[0];
if(gp.buttons[0].value > 0 || gp.buttons[0].pressed == true) {
b--;
} else if(gp.buttons[1].value > 0 || gp.buttons[1].pressed == true) {
a++;
} else if(gp.buttons[2].value > 0 || gp.buttons[2].pressed == true) {
b++;
} else if(gp.buttons[3].value > 0 || gp.buttons[3].pressed == true) {
a--;
}
}
ball.style.left = a*2 + "px";
ball.style.top = b*2 + "px";
var start = gameLoop();
};
二、Performance API
简介:使用performance能够方便js开发人员实时观测页面性能,支持应用程序内的客户端延迟测量。性能接口被认为是高效的,因为它们精确到千分之一毫秒(精确到到5µs(微秒),受硬件或软件约束)。这些接口支持许多特性,包括计算帧速率(在动画中可能很重要)和基准测试(例如加载资源的时间)。目前支持度最高的是chrome浏览器,其他浏览器部分功能不支持。
由下图可以看出,通过performance API我们能够处理以下处理阶段:页面卸载(无前一个网页 unload ,则startTime与 fetchStart 值相等)->页面重定向(重定向开始时会涉及到unload)->拉取缓存(在http请求抓取文档时,检查缓存)->查询DNS(如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 拉取缓存值相等)->发起TCP请求(只建立连接)->request(完成连接建立发送请求)->response(响应完成,包括从本地读取缓存)->解析渲染 DOM 树(此时 Document.readyState 变为 loading,并将抛出 readystatechange 相关事件)->网页资源加载并执行->页面加载完成
performance常用计算:
DNS查询耗时:domainLookupEnd - domainLookupStart
TCP链接耗时 :connectEnd - connectStart
request请求耗时:responseEnd - responseStart
解析dom树耗时:domComplete - domInteractive
白屏时间:responseStart - navigationStart
domready时间(用户可操作时间节点) :domContentLoadedEventEnd - navigationStart
onload时间(总下载时间) :loadEventEnd - navigationStart
performance.navigation:
该对象包含两个属性redirectCount以及type,旨在说明当前页面是通过什么方式导航过来的。
TYPE参数 | 枚举值 | 描述 |
TYPE_NAVIGATE | 0 | 普通进入,包括:点击链接、在地址栏中输入 URL、表单提交、或者通过除下表中 TYPE_RELOAD 和 TYPE_BACK_FORWARD 的方式初始化脚本。 |
TYPE_RELOAD | 1 | 通过刷新进入,包括:浏览器的刷新按钮、快捷键刷新、location.reload()等方法。 |
TYPE_BACK_FORWARD | 2 | 通过操作历史记录进入,包括:浏览器的前进后退按钮、快捷键操作、history.forward()、history.back()、history.go(num)。 |
TYPE_UNDEFINED | 3 | 其他非以上类型的方式进入。 |
redirectCount:表示到达最终页面前,重定向的次数,但是这个接口有同源策略限制,即仅能检测同源的重定向。
performance.memory(chrome私有属性,其他浏览器不支持):
该属性会返回浏览器内存的使用情况,包括以下几个值:
属性 | 描述 |
jsHeapSizeLimit | 内存大小限制 |
totalJSHeapSize | 可使用的内存 |
usedJSHeapSize | JS对象(包括V8引擎内部对象)占用的内存,不能大于totalJSHeapSize,如果大于,有可能出现了内存泄漏 |
performance.getEntries():
获取所有资源请求的时间数据,这个函数返回一个按startTime排序的对象数组,数组成员除了会自动根据所请求资源的变化而改变以外,还可以用mark(),measure()方法自定义添加,该对象的属性中除了包含资源加载时间还有以下五个属性。
属性 | 描述 | |||||||||||||||||||||
name | 资源名称,是资源的绝对路径或调用mark方法自定义的名称(例:"http://localhost:3004/searchList.html#/searchlist") | |||||||||||||||||||||
startTime | 开始时间 | |||||||||||||||||||||
duration | 加载时间 | |||||||||||||||||||||
entryType | 资源类型,entryType类型不同数组中的对象结构也不同:
| |||||||||||||||||||||
initiatorType | 如何发起请求(即谁发起的请求):
|
performance.mark(name),clearMarks():创建一个DOMHighResTimeStamp
保存在资源缓存数据中,可通过performance.getEntries()
等相关接口获取。name为创建时设置的name值,将会添加到getEntries队列尾。clearMarks清空所有设置的marks。
performance.easure(name, startMark, endMark),clearMeasures():
计算两个mark
之间的时长,创建一个DOMHighResTimeStamp
保存在资源缓存数据中,可通过performance.getEntries()
等相关接口获取。clearMeasures清空所有设置的measure
name
为创建时设置的值startTime
为调用measure
时的时间duration
为两个mark之间的时长
performance.getEntriesByName(name,type):根据参数name
,type
获取一组当前页面已经加载的资源数据。name
的取值对应到资源数据中的name
字段,type
取值对应到资源数据中的entryType
字段。返回值仍是一个数组,这个数组相当于getEntries()方法经过所填参数筛选后的一个子集。
performance.getEntriesByType(type):根据参数type
获取一组当前页面已经加载的资源数据。type
取值对应到资源数据中的entryType
字段。返回值仍是一个数组
performance.clearResourceTimings():该方法无参数无返回值,可以清除目前所有entryType为"resource"的数据,用于写单页应用的统计脚本非常有用。
performance.now():performance.now()是当前时间与performance.timing.navigationStart的时间差,以微秒(百万分之一秒)为单位的时间,与 Date.now()-performance.timing.navigationStart的区别是不受系统程序执行阻塞的影响,因此更加精准。
performance.toJSON():返回一个包含performance
对象所有属性的JSON
对象。
三、IndexedDB
简介:
IndexedDB是一种低级API,同源下可以访问,用于客户端存储大量结构化数据(包括, 文件/ blobs)。该API使用索引来实现对该数据的高性能搜索。虽然 Wev Storage 对于存储较少量的数据很有用,但对于存储更大量的结构化数据来说,这种方法不太有用。IndexedDB提供了一个解决方案。IndexedDB执行的操作是异步执行的。
IndexedDB是一个事务型数据库系统,采用无关系型数据库。 然而,不像RDBMS使用固定列表,IndexedDB是一个基于JavaScript的面向对象的数据库。 IndexedDB允许您存储和检索用键索引的对象;可以存储结构化克隆算法支持的任何对象。 您只需要指定数据库模式,打开与数据库的连接,然后检索和更新一系列交易。
indexDB支持事务,这意味着一系列操作步骤中,只要有一步失效,整个事务就取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据情况。在indexDB中每一个对数据库的操作都是在一个事务中上下文中执行的,事务范围一次影响一个或多个ObjectStore,通过传入一个ObjectStore名字的数组到创建事务范围的函数来定义。例如:db.transaction(storeName,'readWrite')创建事务的第二个参数是事务模式,当请求一个事务时,必须决定是按照只读还是读写模式请求访问。
示例:
//indexDB的使用,异步api
var db, store;
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; //indexDB事物
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange; //主键集合
var request = indexedDB.open('Html5IndexedDB', 2); //创建一个数据库
request.onsuccess = function(e) {
console.log('存在数据库就打开,否则创建');
db = e.target.result;
var transaction;
try {
transaction = db.transaction('users', 'readwrite');
} catch (e) {
console.log('数据库创建失败或者异常~');
}
store = transaction.objectStore('users'); //创建数据库事务
//游标范围
// 只获取3323的数据 IDBKeyRange.only(3323)
store.openCursor(IDBKeyRange.only(3323)).onsuccess = function(event) {
//读取游标数据
var cursor = event.target.result;
var result = [];
if (cursor) {
// cursor.value就是数据对象
// 游标没有遍历完,继续
result.push(cursor.value);
cursor.continue();
} else {
// 如果全部遍历完毕...
return result;
}
};
store.add({ html5: '2', name: '张三', sex: '男', id: '78', age: 24 }); //添加数据
};
request.onerror = function(e) {
console.log(e);
}; //监听错误事件
request.onupgradeneeded = function(event) {
//数据操作
var db = event.target.result;
var objectStore = db.createObjectStore('users', { keyPath: 'html5' });
//创建对象存储空间存放用户信息
objectStore.createIndex('name', 'name', { unique: false });
//创建索引来通过name搜索客户
objectStore.createIndex('id', 'id', { unique: true });
//创建索引来通过email搜索用户
objectStore.add({ html5: '1', name: '小王', sex: '女', id: '3323', age: 23 }); //存入一条用户信息数据
};
四、Long Tasks API
简介:
Long Tasks,这是一个实验性API,它可以直观地告诉我们哪些任务执行耗费了50毫秒或更多时间。阻塞主线程达50毫秒或以上的任务会导致此类问题:严重不稳定的交互行为、严重不稳定的事件回调延迟、紊乱的动画和滚动。长任务是指任何连续不间断的且主UI线程繁忙50毫秒及以上的时间区间(如:长耗时的事件回调,代价高昂的回流和其他重绘,浏览器在超过50毫秒的事件循环的相邻循环之间所做的工作)。下图展示了,观察事件流事件中返回的数据属性
属性 | 取值 | 描述 |
containerType | the top level page(任务发生在其中的顶层页面)、iframe(发生在iframe)、embed(嵌入插槽,如音频视频等)、object(具体对象) | 浏览上下文的容器,具体指发生长任务的位置 |
containerId | - | 发生长任务容器的id |
containerName | - | 发生长任务容器的名称 |
containerSrc | - | 发生长任务容器的属性(通常是containerType为embed) |
示例:
<html>
<head>
<title>Long Tasks API</title>
</head>
<body>
<h5>
Long Tasks,这是一个实验性API,它可以直观地告诉我们哪些任务执行耗费了50毫秒或更多时间。
阻塞主线程达50毫秒或以上的任务会导致此类问题:严重不稳定的交互行为、严重不稳定的事件回调延迟、紊乱的动画和滚动。
长任务是指任何连续不间断的且主UI线程繁忙50毫秒及以上的时间区间(如:长耗时的事件回调,代价高昂的回流和其他重绘,
浏览器在超过50毫秒的事件循环的相邻循环之间所做的工作)。
</h5>
<p>目前尝试使用该属性,但仍然无法定位到具体哪个位置发生了长任务</p>
<h5>演示:</h5>
<button id="button" name="test" onClick="delayAlert()">延迟弹出</button>
<script>
function delayAlert() {
setTimeout(function() {
alert(1);
}, 1000);
}
var observer = new PerformanceObserver(function(list) {
console.log('list:', list);
var perfEntries = list.getEntries();
console.log('perfEntries:', perfEntries);
});
console.log('111233');
// register observer for long task notifications
observer.observe({ entryTypes: ['longtask'] });
</script>
</body>
</html>
五、NetWork Information API
简介:网络状态 API 可以获取到系统的网络连接信息,比如说连接方式是 WiFi 还是蜂窝。应用程序可以根据此信息为用户展现不同清晰度的内容。
示例:
<html>
<head>
<title>NetWork Information API</title>
</head>
<body>
<h5>
NetWork Information API可以获取到系统的网络连接信息,比如说连接方式是 WiFi
还是蜂窝。应用程序可以根据此信息为用户展现不同清晰度的内容 目前部分pc端浏览器支持该api(chrome支持),移动端androd
2.2的webkit浏览器已经支持该api
</h5>
<pre>
var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
var type = connection.type;
function updateConnectionStatus() {
console.log("设备的网络连接从" + type + "变成了" + connection.type);
}
connection.addEventListener('change', updateConnectionStatus);
</pre>
<h5>另外,目前大部分浏览器均已经支持的api为onLine和offLine</h5>
<pre>
if(navigator.onLine){
console.log("网络已连接");
}else{
console.log("网络已断开");
}
window.addEventListener('online',function(){
console.log("网络已连接");
});
window.addEventListener('offline',function(){
console.log("网络已断开");
});
</pre>
<script>
var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
var type = connection.type;
function updateConnectionStatus() {
console.log('设备的网络连接从' + type + '变成了' + connection.type);
}
connection.addEventListener('change', updateConnectionStatus);
</script>
<script>
// 目前已经支持的api
if (navigator.onLine) {
console.log('网络已连接');
} else {
console.log('网络已断开');
}
window.addEventListener('online', function() {
console.log('网络已连接');
});
window.addEventListener('offline', function() {
console.log('网络已断开');
});
</script>
</body>
</html>
六、Page Visibility API
简介:
目前Web API在控制页面的显示隐藏部分有以下几组api,但支持度并不同:
DOMContentLoaded、load、beforeUnload和unload:该组api为dom加载,页面的加载,卸载前以及卸载功能,目前被浏览器广泛支持。DOMContentLoaded在浏览器已经完全加载了HTML,DOM树已经构建完毕时执行,但外部资源没有进行加载(如外部样式表、img未加载,不包括外部js)。通过监听load事件可以用来判断页面是否加载了所有的资源。beforeUnload和unload为页面卸载事件,beforeUnload通常用来在页面卸载前给出部分提示内容,但并不支持异步操作。unload为页面卸载后调用。
pageShow和pageHide:Firefox和Opera有一个新特性,名叫“往返缓存”(back-forward cache,或bfcache),可以在用户使用浏览器的“后退”和“前进”按钮时加快页面的转换速度。缓存中不仅保存着页面数据,还保存了DOM和JavaScript的状态;实际上是将整个页面都保存在了内存里。如果页面位于bfcache中,那么再次打开该页面就不会触发load事件。
visibilityState和hidden:我们传统上对网页关闭的监听都是基于上述的几种,但在手机端行为确并不一样,因为手机端可以通过home键进行部分pc端观测不到的操作,因此衍生出visibilityState等状态处理的api。这个新的 API 的意义在于,通过监听网页的可见性,可以预判网页的卸载,还可以用来节省资源,减缓电能的消耗。document.visibilityState属性返回一个字符串,表示页面当前的可见性状态,共有三个可能的值:hidden(页面彻底不可见), visible(页面部分可见),prerender(页面即将或正在渲染,处于不可见状态),unloaded(页面正在从内存中卸载)。其中hidden和visible基本上所有浏览器均支持,prerender需要支持预渲染的浏览器才支持。
visibilitychange
事件比pagehide
、beforeunload
、unload
事件更可靠,因为它能够完整的监听到所有页面卸载的行为
通过document对象也同样能够读取到当前页面的显示状态。通过document.hidden将会返回boolean类型的值,true代表页面已经被隐藏活或卸载,false代表页面正在显示。document.visibilityState返回一个用来展示文档可见性状态的字符串。取值为hidden,visible,prerender,unloaded。
示例:
/**
* 示例:
* DOMContentLoaded 由 document 对象触发,当浏览器在解析HTML页面时遇到了script标签,将无法继续构
* 建DOM树,必须立即执行脚本。外部脚本(带src的)的加载和解析也会暂停DOM树构建,所以
* DOMContentLoaded 也会等待外部脚本。
* 不过有两个例外是带async和defer的外部脚本,他们告诉浏览器继续解析而不需要等待脚本的执行,所以用户
* 可以在脚本加载完成前可以看到页面,有较好的用户体验
*/
function ready() {
alert('DOM is ready');
}
document.addEventListener("DOMContentLoaded", ready);
/**
* 示例:
* window对象上的onload事件在所有文件包括样式表,图片和其他资源下载完毕后触发
*/
window.onload = function() {
alert('Page loaded');
};
/**
* 示例:onunload
* 用户离开页面的时候,window对象上的unload事件会被触发,我们可以做一些不存在延迟的事情,比如关闭
* 弹出的窗口,可是我们无法阻止用户转移到另一个页面上。
*/
/**
* 示例:onbeforeunload
* 如果用户即将离开页面或者关闭窗口时,beforeunload事件将会被触发以进行额外的确认。
*/
window.onbeforeunload = function() {
return "There are unsaved changes. Leave now?";
};
/**
* 示例:pageshow
* 基于浏览器的bfcache功能,新增api
* pageshow在页面显示时触发,无论页面是否来自bfcache。pageshow都会在load事件触发后触发
*/
(function(){
var showCount = 0;
window.addEventListener('pageshow',function(event){
//event.persisted 如果页面保存在了bfcache中,属性值为true;否则,属性值为false。
showCount++;
alert("Show has been fired " + showCount + " times.");
})
})();
/**
* 示例:pagehide
* 页面切换到下一个页面,会触发pagehide
*/
window.addEventListener('hide',function(event){
//event.persisted 如果页面保存在了bfcache中,属性值为true;否则,属性值为false。
alert("Hiding. Persisted? " + event.persisted);
})
/**
* 示例:document.visibilityState
* 该属性返回一个字符串,表示页面当前的可见性状态,共有三个可能的值。hidden(页面彻底不可见),
* visible(页面部分可见),prerender(页面即将或正在渲染,处于不可见状态),unloaded(页面正在从内存中卸载)
*/
document.addEventListener('visibilitychange', function () {
// 用户离开了当前页面
if (document.visibilityState === 'hidden') {
document.title = '页面不可见';
}
// 用户打开或回到页面
if (document.visibilityState === 'visible') {
document.title = '页面可见';
}
});