ES2020 新特性(種草)
這幾年,Ecma TC39一年一次更新 ecmascript 規(guī)范標準,截止目前,以下特性已進入 finished 狀態(tài)?,F(xiàn)在帶大家體驗種草 ES2020 新特性。
一:Promise.allSettled
Promise.all 缺陷
都知道 Promise.all 具有并發(fā)執(zhí)行異步任務的能力。但它的最大問題就是如果其中某個任務出現(xiàn)異常(reject),所有任務都會掛掉,Promise直接進入 reject 狀態(tài)。
想象這個場景:你的頁面有三個區(qū)域,分別對應三個獨立的接口數(shù)據(jù),使用 Promise.all 來并發(fā)三個接口,如果其中任意一個接口服務異常,狀態(tài)是reject,這會導致頁面中該三個區(qū)域數(shù)據(jù)全都無法渲染出來,因為任何 reject 都會進入catch回調(diào), 很明顯,這是無法接受的,如下:
Promise.all([
Promise.reject({code: 500, msg: '服務異常'}),
Promise.resolve({ code: 200, list: []}),
Promise.resolve({code: 200, list: []})
])
.then((ret) => {
// 如果其中一個任務是 reject,則不會執(zhí)行到這個回調(diào)。
RenderContent(ret);
})
.catch((error) => {
// 本例中會執(zhí)行到這個回調(diào)
// error: {code: 500, msg: "服務異常"}
})
我們需要一種機制,如果并發(fā)任務中,無論一個任務正?;蛘弋惓?,都會返回對應的的狀態(tài)(fulfilled 或者 rejected)與結(jié)果(業(yè)務value 或者 拒因 reason),在 then 里面通過 filter 來過濾出想要的業(yè)務邏輯結(jié)果,這就能最大限度的保障業(yè)務當前狀態(tài)的可訪問性,而 Promise.allSettled 就是解決這問題的。
Promise.allSettled([
Promise.reject({code: 500, msg: '服務異常'}),
Promise.resolve({ code: 200, list: []}),
Promise.resolve({code: 200, list: []})
])
.then((ret) => {
/*
0: {status: "rejected", reason: {…}}
1: {status: "fulfilled", value: {…}}
2: {status: "fulfilled", value: {…}}
*/
// 過濾掉 rejected 狀態(tài),盡可能多的保證頁面區(qū)域數(shù)據(jù)渲染
RenderContent(ret.filter((el) => {
return el.status !== 'rejected';
}));
});
二:可選鏈(Optional chaining)
可選鏈 可讓我們在查詢具有多層級的對象時,不再需要進行冗余的各種前置校驗。
日常開發(fā)中,我們經(jīng)常會遇到這種查詢
var name = user && user.info && user.info.name;
又或是這種
var age = user && user.info && user.info.getAge && user.info.getAge();
這是一種丑陋但又不得不做的前置校驗,否則很容易命中 Uncaught TypeError: Cannot read property... 這種錯誤,這極有可能讓你整個應用掛掉。
用了 Optional Chaining ,上面代碼會變成
var name = user?.info?.name;
var age = user?.info?.getAge?.();
可選鏈中的 ? 表示如果問號左邊表達式有值, 就會繼續(xù)查詢問號后面的字段。根據(jù)上面可以看出,用可選鏈可以大量簡化類似繁瑣的前置校驗操作,而且更安全。
三:空值合并運算符(Nullish coalescing Operator)
當我們查詢某個屬性時,經(jīng)常會遇到,如果沒有該屬性就會設(shè)置一個默認的值。比如下面代碼中查詢玩家等級。
var level = (user.data && user.data.level) || '暫無等級';
在JS中,空字符串、0 等,當進行邏輯操作符判時,會自動轉(zhuǎn)化為 false。在上面的代碼里,如果玩家等級本身就是 0 級, 變量 level 就會被賦值 暫無等級 字符串,這是邏輯錯誤。
var level;
if (typeof user.level === 'number') {
level = user.level;
} else if (!user.level) {
level = '暫無等級';
} else {
level = user.level;
}
來看看用空值合并運算符如何處理
// {
// "level": 0
// }
var level = `${user.level}級` ?? '暫無等級';
// level -> '0級'
用空值合并運算在邏輯正確的前提下,代碼更加簡潔。
空值合并運算符 與 可選鏈 相結(jié)合,可以很輕松處理多級查詢并賦予默認值問題。
var level = user.data?.level ?? '暫無等級';
四:dynamic-import
按需 import 提案幾年前就已提出,如今終于能進入ES正式規(guī)范。這里個人理解成“按需”更為貼切?,F(xiàn)代前端打包資源越來越大,打包成幾M的JS資源已成常態(tài),而往往前端應用初始化時根本不需要全量加載邏輯資源,為了首屏渲染速度更快,很多時候都是按需加載,比如懶加載圖片等。而這些按需執(zhí)行邏輯資源都體現(xiàn)在某一個事件回調(diào)中去加載。
el.onclick = () => {
import(`/path/current-logic.js`)
.then((module) => {
module.doSomthing();
})
.catch((err) => {
// load error;
})
}
當然,webpack目前已很好的支持了該特性。
五:globalThis
Javascript 在不同的環(huán)境獲取全局對象有不通的方式,node 中通過 global, web中通過 window, self 等,有些甚至通過 this 獲取,但通過 this 是及其危險的,this 在 js 中異常復雜,它嚴重依賴當前的執(zhí)行上下文,這些無疑增加了獲取全局對象的復雜性。
過去獲取全局對象,可通過一個全局函數(shù)
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
var globals = getGlobal();
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/globalThis
而 globalThis 目的就是提供一種標準化方式訪問全局對象,有了 globalThis 后,你可以在任意上下文,任意時刻都能獲取到全局對象。
六:BigInt
Js 中 Number類型只能安全的表示-(2^53-1)至 2^53-1 范的值,即Number.MIN_SAFE_INTEGER 至Number.MAX_SAFE_INTEGER,超出這個范圍的整數(shù)計算或者表示會丟失精度。
var num = Number.MAX_SAFE_INTEGER; // -> 9007199254740991 num = num + 1; // -> 9007199254740992 // 再次加 +1 后無法正常運算 num = num + 1; // -> 9007199254740992 // 兩個不同的值,卻返回了true 9007199254740992 === 9007199254740993 // -> true
為解決此問題,ES2020提供一種新的數(shù)據(jù)類型:BigInt。
使用 BigInt 有兩種方式:
在整數(shù)字面量后面加n。
var bigIntNum = 9007199254740993n;
使用 BigInt 函數(shù)。
var bigIntNum = BigInt(9007199254740);
var anOtherBigIntNum = BigInt('9007199254740993');
通過 BigInt, 我們可以安全的進行大數(shù)整型計算。
var bigNumRet = 9007199254740993n + 9007199254740993n; // -> -> 18014398509481986n bigNumRet.toString(); // -> '18014398509481986'
注意:
BigInt 是一種新的數(shù)據(jù)原始(primitive)類型。
typeof 9007199254740993n; // -> 'bigint'
盡可能避免通過調(diào)用函數(shù) BigInt 方式來實例化超大整型。因為參數(shù)的字面量實際也是 Number 類型的一次實例化,超出安全范圍的數(shù)字,可能會引起精度丟失。
七:String.prototype.matchAll
思考下面代碼
var str = '<text>JS</text><text>正則</text>'; var reg = /<\w+>(.*?)<\/\w+>/g; console.log(str.match(reg)); // -> ["<text>JS</text>", "<text>正則</text>"]
可以看出返回的數(shù)組里包含了父匹配項,但未匹配到子項(group)。移除全局搜索符“g”試試。
var str = '<text>JS</text><text>正則</text>'; // 注意這里沒有全局搜素標示符“g” var reg = /<\w+>(.*?)<\/\w+>/; console.log(str.match(reg)); // 上面會打印出 /* [ "<text>JS</text>", "JS", index: 0, input: "<text>JS</text><text>正則</text>", groups: undefined ] */
這樣可以獲取到匹配的父項,包括子項(group),但只能獲取到第一個滿足的匹配字符。能看出上面無法匹配到<text>正則</text>。
如果獲取到全局所有匹配項,包括子項呢?
ES2020提供了一種簡易的方式:String.prototype.matchAll, 該方法會返回一個迭代器。
var str = '<text>JS</text><text>正則</text>';
var allMatchs = str.matchAll(/<\w+>(.*?)<\/\w+>/g);
for (const match of allMatchs) {
console.log(match);
}
/*
第一次迭代返回:
[
"<text>JS</text>",
"JS",
index: 0,
input: "<text>JS</text><text>正則</text>",
groups: undefined
]
第二次迭代返回:
[
"<text>正則</text>",
"正則",
index: 15,
input: "<text>JS</text><text>正則</text>",
groups: undefined
]
*/
能看出每次迭代中可獲取所有的匹配,以及本次匹配的成功的一些其他元信息。
參考資料
github.com/tc39/proposals/blob/master/finished-proposals.md
prop-tc39.now.sh/
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
全面了解構(gòu)造函數(shù)繼承關(guān)鍵apply call
下面小編就為大家?guī)硪黄媪私鈽?gòu)造函數(shù)繼承關(guān)鍵apply call。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-07-07
微信小程序?qū)崿F(xiàn)富文本圖片寬度自適應的方法
小程序里圖片會顯示不全,這時就應該做相應的處理,使小程序里圖片顯示正確,這篇文章主要介紹了微信小程序?qū)崿F(xiàn)富文本圖片寬度自適應的方法,感興趣的小伙伴們可以參考一下2019-01-01
利用NodeJS和PhantomJS抓取網(wǎng)站頁面信息以及網(wǎng)站截圖
這篇文章主要介紹了利用NodeJS和PhantomJS抓取網(wǎng)站頁面信息以及網(wǎng)站截圖的方法,提供實例代碼供大家參考2013-11-11

