ES7 和 ES8 出來的時(shí)間已經(jīng)蠻長了,對(duì)于瀏覽器的支持也比較好,正巧昨天在調(diào)研如何優(yōu)化 web-worker 的時(shí)候看到了一個(gè)新特性,順便與大家分享一下,大佬勿噴
ES7
在 ES7 中,只新增了數(shù)組的 includes 和簡寫的位運(yùn)算符,我來給大家舉個(gè)例子吧
1.Array.prototype.includes(value, formIndex)
- 該方法確定確定某一個(gè)值是否存在于當(dāng)前數(shù)組中
參數(shù)
value: 需要查找的值formIndex: 從指定位置開始查找
返回值
- 返回值是一個(gè)
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
// 當(dāng)我們知道查詢的值大概范圍時(shí) (吐槽一下:一直覺得這個(gè)參數(shù)雞肋的一批)
// formIndex > 數(shù)組長度
console.log(arr.includes(2,5)) // 返回 false
// formIndex < 0
console.log(arr.includes(2, -1)) // 返回 false
console.log(arr.includes(2, -3)) // 返回 true
注:這個(gè)地方有一個(gè)它內(nèi)置的計(jì)算公示: arr.length + formIndex <= arr.length 如果上述條件滿足,將從計(jì)算后的位置查詢當(dāng)前值,不滿足的話,會(huì)從整個(gè)數(shù)組中查詢
2.指數(shù)運(yùn)算簡寫 **
- 原來我們?cè)谟?jì)算 2 的 10 次方時(shí),寫法一般都是這樣的
const num1 = Math.pow(2, 10)
- 那其實(shí)我們現(xiàn)在可以這樣去寫
const num2 = 2 ** 10
// 驗(yàn)證一下是否相等
console.log(num1 === num2) // 返回 true
- 這樣去寫的話,是不是又可以少寫幾個(gè)字母了~~
ES8
ES8 中我們現(xiàn)在用的最多的首當(dāng)其沖是 async/await 了,那其實(shí)還有很多有意思的東西,我們可以看看
1.async/await
我們分開介紹吧
-
async這個(gè)關(guān)鍵字可以將一個(gè)function聲明成為一個(gè)異步方法,返回值是一個(gè)Promise
async function getNumber(num) {
return num + 10
}
// 同樣的方法可以寫成這樣
const getNumber = async (num) => {
return num + 10
}
console.log(getNumber(10)) // 返回 Promise {<fulfilled>: 20}
- 如果返回值是一個(gè)
promise的話,我們其實(shí)獲取值也可以這樣寫
getNumber(10).then(res => console.log(res))
-
await這個(gè)關(guān)鍵字和async一起使用的時(shí)候就體現(xiàn)出了優(yōu)勢。該關(guān)鍵字只能在 異步函數(shù) 中才會(huì)起作用
function promiseFn() {
return new Promise(resolve => {
setTimeout(() => {
resolve("result");
}, 1500);
});
}
async function fn() {
let res = await promiseFn();
console.log("異步代碼執(zhí)行完畢", res);
}
fn(); // wait 1.5s 后,打印 異步代碼執(zhí)行完畢, result
注:多個(gè)異步方法需要同時(shí)執(zhí)行,可以使用 await Promise.all[promise1,promise2]
2.Object.values() 和 Object.entries()
Object.values() 方法返回一個(gè)給定對(duì)象自身所有的 key,其中是不包含繼承來的 key
Object.entries() 方法返回一個(gè)數(shù)組,包含當(dāng)前Object中自身所有鍵值對(duì),同樣不包含繼承來的值
const obj = { name: 'tal', age: 17 };
console.log(Object.values(obj)); //返回 ['tal', 17]
console.log(Object.entries(obj)); //返回 [['name', 'tal'],['age', 17]]
// 其實(shí)對(duì)于我們平常開發(fā)來說,還是提高了一些效率的
// 例如:遍歷對(duì)象的鍵值
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key}-${value}`);
});
// 如果傳入的是字符串會(huì)怎樣
Object.values('tal') //返回 ["t", "a", "l"]
Object.entries('tal') // 返回 [['0': 't'], ['1': 'a'], ['2': 'l']]
注: 在使用這兩個(gè)屬性時(shí),會(huì)發(fā)生一個(gè)隱式的類型轉(zhuǎn)化,將我們傳入的值轉(zhuǎn)為 Object 后,再執(zhí)行方法
3.String padding
String 新增了兩個(gè)實(shí)例函數(shù) String.prototype.padStart 和 String.prototype.padEnd ,允許將空字符串或其他字符串添加到原始字符串的開頭或結(jié)尾。
參數(shù)
- targetLength: 當(dāng)前字符串需要填充到的目標(biāo)長度。如果這個(gè)數(shù)值小于當(dāng)前字符串的長度,則返回當(dāng)前字符串本身。
- padString: (可選)填充字符串。如果字符串太長,使填充后的字符串長度超過了目標(biāo)長度,則只保留最左側(cè)的部分,其他部分會(huì)被截?cái)啵藚?shù)的缺省值為 ' '。
// 簡單寫法
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.結(jié)尾支持逗號(hào)
這個(gè)功能其實(shí)對(duì)于我們來說還是比較友好的
例如:一個(gè)方法或者對(duì)象,我們只是增加了一個(gè)屬性或者參數(shù),我們需要在最末尾先增加一個(gè)逗號(hào)后再添加新屬性或者參數(shù),這樣的話,在 git 上就會(huì)出現(xiàn)兩行改動(dòng),不是很友好
function fn(
para1: number,
para: number,
){
console.log(para1,para);
}
fn(1,2);
let obj = {
n:'',
n:'',
}
在支持這樣的語法后,我們就可以改一下我們的格式化工具了,避免了提交中會(huì)多出的一些改動(dòng)
5.Object.getOwnPropertyDescriptors()
該函數(shù)函數(shù)用來獲取一個(gè)對(duì)象的所有自身屬性的描述符,如果沒有任何自身屬性,則返回空對(duì)象。
const obj = {
name: "tal",
get fn() {
return "fn";
}
};
const obj1 = {}
console.log(Object.getOwnPropertyDescriptors(obj1))
console.log(Object.getOwnPropertyDescriptors(obj))
- SharedArrayBuffer 與 Atomics
整個(gè)梳理了一遍 ES7 和 ES8 的東西后,終于開始聊重頭戲了,在用 web-worker 的老師們,可以看看這個(gè)東西是不是正好滿足了你當(dāng)前的需求
是不是還在為 worker 線程不能直接獲取到主線程的變量而苦惱
是不是還在頻繁的使用 postMessage 而感到繁瑣
嘗試一下 SharedArrayBuffer 吧(好像一段廣告詞...)
直接上代碼
// 這里是主進(jìn)程代碼
// 創(chuàng)建一個(gè)worker進(jìn)程
const worker = new Worker("./worker.js");
// 新建1kb內(nèi)存
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 發(fā)送的共享內(nèi)存地址
worker.postMessage(intArrBuffer);
worker.onmessage = function(e) {
console.log("更改后的數(shù)據(jù)", 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
};
這段代碼實(shí)際就是在內(nèi)存中創(chuàng)建了一個(gè) 1kb 的內(nèi)存,然后我將其中的內(nèi)容循環(huán)改成數(shù)字后,發(fā)送給子進(jìn)程(還是需要 PostMessage )的,但是內(nèi)存中的讀寫速度要比使用 PostMessage 快了很多,感興趣的老師可以試試
SharedArrayBuffer 是 js 開啟多線程的第一步,一提到多線程,我們一定會(huì)想到競爭,同樣的去修改同一個(gè)變量下的同一個(gè)元素怎么辦?答:多個(gè)共享內(nèi)存的線程能夠同時(shí)讀寫同一位置上的數(shù)據(jù)。原子操作會(huì)確保正在讀或?qū)懙臄?shù)據(jù)的值是符合預(yù)期的,即下一個(gè)原子操作一定會(huì)在上一個(gè)原子操作結(jié)束后才會(huì)開始,其操作過程不會(huì)中斷。
這個(gè)時(shí)候就出現(xiàn)了 Atomics, 它對(duì)象提供了一組靜態(tài)方法用來對(duì) SharedArrayBuffer 對(duì)象進(jìn)行原子操作。這些原子操作屬于 Atomics 模塊。與一般的全局對(duì)象不同,Atomics 不是構(gòu)造函數(shù),因此不能使用 new 操作符調(diào)用,也不能將其當(dāng)作函數(shù)直接調(diào)用。Atomics 的所有屬性和方法都是靜態(tài)的。
我們來看看它有什么方法:
- Atomics.add() 將指定位置上的數(shù)組元素與給定的值相加,并返回相加前的值
- Atomics.and() 將指定位置上的數(shù)組元素與給定的值相與,返回操作前的值
- Atomics.load() 返回?cái)?shù)組中指定位置的值
- Atomics.store() 改動(dòng)其中的某個(gè)值,并返回改動(dòng)后的值
- Atomics.wait() 如果當(dāng)前的值等于給定的值,線程會(huì)被阻塞等待
- Atomics.notify() 將當(dāng)前等待的進(jìn)程喚醒
...
它提供的方法還是很多的,剩下的留給大佬們自己實(shí)踐一下(測試的時(shí)候需要啟動(dòng)服務(wù)哈,worke需要)...