ES7 和 ES8 出来的时间已经蛮长了,对于浏览器的支持也比较好,正巧昨天在调研如何优化 web-worker 的时候看到了一个新特性,顺便与大家分享一下,大佬勿喷
ES7
在 ES7 中,只新增了数组的 includes
和简写的位运算符,我来给大家举个例子吧
1.Array.prototype.includes(value, formIndex)
- 该方法确定确定某一个值是否存在于当前数组中
参数
value
: 需要查找的值formIndex
: 从指定位置开始查找
返回值
- 返回值是一个
Boolean
值,true
代表包含,false
代表不包含
const arr = [1, 2, 3, NaN]
// 最简单使用
console.log(arr.includes(2)) // 返回 true
console.log(arr.includes(5)) // 返回 false
console.log(arr.includes(NaN)) // 返回 true
// 当我们知道查询的值大概范围时 (吐槽一下:一直觉得这个参数鸡肋的一批)
// formIndex > 数组长度
console.log(arr.includes(2,5)) // 返回 false
// formIndex < 0
console.log(arr.includes(2, -1)) // 返回 false
console.log(arr.includes(2, -3)) // 返回 true
注:这个地方有一个它内置的计算公示: arr.length + formIndex <= arr.length 如果上述条件满足,将从计算后的位置查询当前值,不满足的话,会从整个数组中查询
2.指数运算简写 **
- 原来我们在计算 2 的 10 次方时,写法一般都是这样的
const num1 = Math.pow(2, 10)
- 那其实我们现在可以这样去写
const num2 = 2 ** 10
// 验证一下是否相等
console.log(num1 === num2) // 返回 true
- 这样去写的话,是不是又可以少写几个字母了~~
ES8
ES8 中我们现在用的最多的首当其冲是 async/await
了,那其实还有很多有意思的东西,我们可以看看
1.async/await
我们分开介绍吧
-
async
这个关键字可以将一个function
声明成为一个异步方法,返回值是一个Promise
async function getNumber(num) {
return num + 10
}
// 同样的方法可以写成这样
const getNumber = async (num) => {
return num + 10
}
console.log(getNumber(10)) // 返回 Promise {: 20}
- 如果返回值是一个
promise
的话,我们其实获取值也可以这样写
getNumber(10).then(res => console.log(res))
-
await
这个关键字和async
一起使用的时候就体现出了优势。该关键字只能在 异步函数 中才会起作用
function promiseFn() {
return new Promise(resolve => {
setTimeout(() => {
resolve("result");
}, 1500);
});
}
async function fn() {
let res = await promiseFn();
console.log("异步代码执行完毕", res);
}
fn(); // wait 1.5s 后,打印 异步代码执行完毕, result
注:多个异步方法需要同时执行,可以使用 await Promise.all[promise1,promise2]
2.Object.values() 和 Object.entries()
Object.values() 方法返回一个给定对象自身所有的 key,其中是不包含继承来的 key
Object.entries() 方法返回一个数组,包含当前Object中自身所有键值对,同样不包含继承来的值
const obj = { name: 'tal', age: 17 };
console.log(Object.values(obj)); //返回 ['tal', 17]
console.log(Object.entries(obj)); //返回 [['name', 'tal'],['age', 17]]
// 其实对于我们平常开发来说,还是提高了一些效率的
// 例如:遍历对象的键值
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key}-${value}`);
});
// 如果传入的是字符串会怎样
Object.values('tal') //返回 ["t", "a", "l"]
Object.entries('tal') // 返回 [['0': 't'], ['1': 'a'], ['2': 'l']]
注: 在使用这两个属性时,会发生一个隐式的类型转化,将我们传入的值转为 Object 后,再执行方法
3.String padding
String
新增了两个实例函数 String.prototype.padStart
和 String.prototype.padEnd
,允许将空字符串或其他字符串添加到原始字符串的开头或结尾。
参数
- targetLength: 当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。
- padString: (可选)填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断,此参数的缺省值为 ' '。
// 简单写法
console.log('0.0'.padStart(4,'10')) //返回 10.0
console.log('0.0'.padEnd(4,'0')) //返回 0.00
console.log('0.0'.padStart(20)) //返回 0.00
console.log('0.0'.padEnd(10,'0')) //返回 0.00000000
4.结尾支持逗号
这个功能其实对于我们来说还是比较友好的
例如:一个方法或者对象,我们只是增加了一个属性或者参数,我们需要在最末尾先增加一个逗号后再添加新属性或者参数,这样的话,在 git
上就会出现两行改动,不是很友好
function fn(
para1: number,
para: number,
){
console.log(para1,para);
}
fn(1,2);
let obj = {
n:'',
n:'',
}
在支持这样的语法后,我们就可以改一下我们的格式化工具了,避免了提交中会多出的一些改动
5.Object.getOwnPropertyDescriptors()
该函数函数用来获取一个对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。
const obj = {
name: "tal",
get fn() {
return "fn";
}
};
const obj1 = {}
console.log(Object.getOwnPropertyDescriptors(obj1))
console.log(Object.getOwnPropertyDescriptors(obj))
- SharedArrayBuffer 与 Atomics
整个梳理了一遍 ES7 和 ES8 的东西后,终于开始聊重头戏了,在用 web-worker
的老师们,可以看看这个东西是不是正好满足了你当前的需求
是不是还在为 worker
线程不能直接获取到主线程的变量而苦恼
是不是还在频繁的使用 postMessage
而感到繁琐
尝试一下 SharedArrayBuffer
吧(好像一段广告词...)
直接上代码
// 这里是主进程代码
// 创建一个worker进程
const worker = new Worker("./worker.js");
// 新建1kb内存
const sharedBuffer = new SharedArrayBuffer(1024);
// 建视图
const intArrBuffer = new Int32Array(sharedBuffer);
for (let i = 0; i < intArrBuffer.length; i++) {
intArrBuffer[i] = i;
}
// console.log(sharedBuffer);
// postMessage 发送的共享内存地址
worker.postMessage(intArrBuffer);
worker.onmessage = function(e) {
console.log("更改后的数据", Atomics.load(intArrBuffer, 20)); // 返回 99
};
// 这里是 worker 的代码
onmessage = function(e) {
let arrBuffer = e.data; // 这里就可以获取到
console.log(Atomics.load(arrBuffer, 20))
// 我们改一下它
Atomics.store(arrBuffer, 20, 99); // 返回 99
};
这段代码实际就是在内存中创建了一个 1kb 的内存,然后我将其中的内容循环改成数字后,发送给子进程(还是需要 PostMessage )的,但是内存中的读写速度要比使用 PostMessage 快了很多,感兴趣的老师可以试试
SharedArrayBuffer
是 js 开启多线程的第一步,一提到多线程,我们一定会想到竞争,同样的去修改同一个变量下的同一个元素怎么办?答:多个共享内存的线程能够同时读写同一位置上的数据。原子操作会确保正在读或写的数据的值是符合预期的,即下一个原子操作一定会在上一个原子操作结束后才会开始,其操作过程不会中断。
这个时候就出现了 Atomics
, 它对象提供了一组静态方法用来对 SharedArrayBuffer
对象进行原子操作。这些原子操作属于 Atomics
模块。与一般的全局对象不同,Atomics
不是构造函数,因此不能使用 new
操作符调用,也不能将其当作函数直接调用。Atomics
的所有属性和方法都是静态的。
我们来看看它有什么方法:
- Atomics.add() 将指定位置上的数组元素与给定的值相加,并返回相加前的值
- Atomics.and() 将指定位置上的数组元素与给定的值相与,返回操作前的值
- Atomics.load() 返回数组中指定位置的值
- Atomics.store() 改动其中的某个值,并返回改动后的值
- Atomics.wait() 如果当前的值等于给定的值,线程会被阻塞等待
- Atomics.notify() 将当前等待的进程唤醒
...
它提供的方法还是很多的,剩下的留给大佬们自己实践一下(测试的时候需要启动服务哈,worke需要)...