ES2020 新特性(种草)


Posted in Javascript onJanuary 12, 2020

这几年,Ecma TC39一年一次更新 ecmascript 规范标准,截止目前,以下特性已进入 finished 状态。现在带大家体验种草 ES2020 新特性。

一:Promise.allSettled

Promise.all 缺陷

都知道 Promise.all 具有并发执行异步任务的能力。但它的最大问题就是如果其中某个任务出现异常(reject),所有任务都会挂掉,Promise直接进入 reject  状态。

想象这个场景:你的页面有三个区域,分别对应三个独立的接口数据,使用 Promise.all 来并发三个接口,如果其中任意一个接口服务异常,状态是reject,这会导致页面中该三个区域数据全都无法渲染出来,因为任何 reject 都会进入catch回调, 很明显,这是无法接受的,如下:

Promise.all([
  Promise.reject({code: 500, msg: '服务异常'}),
  Promise.resolve({ code: 200, list: []}),
  Promise.resolve({code: 200, list: []})
])
.then((ret) => {
  // 如果其中一个任务是 reject,则不会执行到这个回调。
  RenderContent(ret);
})
.catch((error) => {
  // 本例中会执行到这个回调
  // error: {code: 500, msg: "服务异常"}
})

我们需要一种机制,如果并发任务中,无论一个任务正常或者异常,都会返回对应的的状态(fulfilled 或者 rejected)与结果(业务value 或者 拒因 reason),在 then 里面通过 filter 来过滤出想要的业务逻辑结果,这就能最大限度的保障业务当前状态的可访问性,而 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 状态,尽可能多的保证页面区域数据渲染
  RenderContent(ret.filter((el) => {
    return el.status !== 'rejected';
  }));
});

二:可选链(Optional chaining)

可选链 可让我们在查询具有多层级的对象时,不再需要进行冗余的各种前置校验。

日常开发中,我们经常会遇到这种查询

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?.();

可选链中的 ? 表示如果问号左边表达式有值, 就会继续查询问号后面的字段。根据上面可以看出,用可选链可以大量简化类似繁琐的前置校验操作,而且更安全。

三:空值合并运算符(Nullish coalescing Operator)

当我们查询某个属性时,经常会遇到,如果没有该属性就会设置一个默认的值。比如下面代码中查询玩家等级。

var level = (user.data && user.data.level) || '暂无等级';

在JS中,空字符串、0 等,当进行逻辑操作符判时,会自动转化为 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级'

用空值合并运算在逻辑正确的前提下,代码更加简洁。

空值合并运算符 与 可选链 相结合,可以很轻松处理多级查询并赋予默认值问题。

var level = user.data?.level ?? '暂无等级';

四:dynamic-import

按需 import 提案几年前就已提出,如今终于能进入ES正式规范。这里个人理解成“按需”更为贴切。现代前端打包资源越来越大,打包成几M的JS资源已成常态,而往往前端应用初始化时根本不需要全量加载逻辑资源,为了首屏渲染速度更快,很多时候都是按需加载,比如懒加载图片等。而这些按需执行逻辑资源都体现在某一个事件回调中去加载。

el.onclick = () => {
  import(`/path/current-logic.js`)
  .then((module) => {
    module.doSomthing();
  })
  .catch((err) => {
    // load error;
  })
}

当然,webpack目前已很好的支持了该特性。

五:globalThis

Javascript 在不同的环境获取全局对象有不通的方式,node 中通过 global, web中通过 window, self 等,有些甚至通过 this 获取,但通过 this 是及其危险的,this 在 js 中异常复杂,它严重依赖当前的执行上下文,这些无疑增加了获取全局对象的复杂性。

过去获取全局对象,可通过一个全局函数

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,超出这个范围的整数计算或者表示会丢失精度。

var num = Number.MAX_SAFE_INTEGER; // -> 9007199254740991

num = num + 1; // -> 9007199254740992

// 再次加 +1 后无法正常运算
num = num + 1; // -> 9007199254740992

// 两个不同的值,却返回了true
9007199254740992 === 9007199254740993 // -> true

为解决此问题,ES2020提供一种新的数据类型:BigInt。

使用 BigInt 有两种方式:

在整数字面量后面加n。

var bigIntNum = 9007199254740993n;

使用 BigInt 函数。

var bigIntNum = BigInt(9007199254740);
var anOtherBigIntNum = BigInt('9007199254740993');

通过 BigInt, 我们可以安全的进行大数整型计算。

var bigNumRet = 9007199254740993n + 9007199254740993n; // -> -> 18014398509481986n

bigNumRet.toString(); // -> '18014398509481986'

注意:

BigInt 是一种新的数据原始(primitive)类型。

typeof 9007199254740993n; // -> 'bigint'

尽可能避免通过调用函数 BigInt 方式来实例化超大整型。因为参数的字面量实际也是 Number 类型的一次实例化,超出安全范围的数字,可能会引起精度丢失。

七: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>"]

可以看出返回的数组里包含了父匹配项,但未匹配到子项(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/

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
随机显示经典句子或诗歌的javascript脚本
Aug 04 Javascript
cloudgamer出品ImageZoom 图片放大效果
Apr 01 Javascript
用js判断页面刷新或关闭的方法(onbeforeunload与onunload事件)
Jun 22 Javascript
JS控制网页动态生成任意行列数表格的方法
Mar 09 Javascript
javascript每日必学之封装
Feb 23 Javascript
深入浅析JavaScript中的作用域和上下文
Mar 26 Javascript
基于Bootstrap实现图片轮播效果
May 22 Javascript
极力推荐10个短小实用的JavaScript代码段
Aug 03 Javascript
Vuejs仿网易云音乐实现听歌及搜索功能
Mar 30 Javascript
Angular 2父子组件数据传递之@ViewChild获取子组件详解
Jul 04 Javascript
JS图片轮播与索引变色功能实例详解
Jul 06 Javascript
Vue.js中的组件系统
May 30 Javascript
在微信小程序中渲染HTML内容3种解决方案及分析与问题解决
Jan 12 #Javascript
es6 for循环中let和var区别详解
Jan 12 #Javascript
js 计数排序的实现示例(升级版)
Jan 12 #Javascript
JS实现动态无缝轮播
Jan 11 #Javascript
原生js实现无缝轮播图
Jan 11 #Javascript
JS实现轮播图效果
Jan 11 #Javascript
js实现带搜索功能的下拉框
Jan 11 #Javascript
You might like
PHP数组及条件,循环语句学习
2012/11/11 PHP
smarty模板引擎之分配数据类型
2015/03/30 PHP
PHP里的单例类写法实例
2015/06/25 PHP
在PHP程序中使用Rust扩展的方法
2015/07/03 PHP
yii2使用ajax返回json的实现方法
2016/05/14 PHP
JavaScipt基本教程之JavaScript语言的基础
2008/01/16 Javascript
Javascript Ajax异步读取RSS文档具体实现
2013/12/12 Javascript
JavaScript中使用stopPropagation函数停止事件传播例子
2014/08/27 Javascript
JavaScript生成随机字符串的方法
2015/03/19 Javascript
跟我学习javascript的异步脚本加载
2015/11/20 Javascript
用jQuery获取table中行id和td值的实现代码
2016/05/19 Javascript
gulp教程_从入门到项目中快速上手使用方法
2017/09/14 Javascript
JS+CSS实现滚动数字时钟效果
2017/12/25 Javascript
微信小程序—setTimeOut定时器的问题及解决
2019/07/26 Javascript
vue 实现购物车总价计算
2019/11/06 Javascript
Vue数字输入框组件使用方法详解
2020/02/10 Javascript
js、jquery实现列表模糊搜索功能过程解析
2020/03/27 jQuery
js节流防抖应用场景,以及在vue中节流防抖的具体实现操作
2020/09/21 Javascript
[01:07:19]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第一场 1月19日
2021/03/11 DOTA
Python最长公共子串算法实例
2015/03/07 Python
在Python中处理字符串之isdigit()方法的使用
2015/05/18 Python
python实现中文分词FMM算法实例
2015/07/10 Python
python中input()与raw_input()的区别分析
2016/02/27 Python
python中将字典形式的数据循环插入Excel
2018/01/16 Python
Python中GIL的使用详解
2018/10/03 Python
Python 读取xml数据,cv2裁剪图片实例
2020/03/10 Python
python实现图像拼接功能
2020/03/23 Python
详解Python 中的 defaultdict 数据类型
2021/02/22 Python
Piercing Pagoda官网:耳环、戒指、项链、手链等
2020/09/28 全球购物
个人委托书怎么写
2014/09/17 职场文书
离婚财产处理协议书
2014/09/30 职场文书
警示教育片观后感
2015/06/17 职场文书
常住证明范本
2015/06/23 职场文书
python数据分析之用sklearn预测糖尿病
2021/04/22 Python
分享提高 Python 代码的可读性的技巧
2022/03/03 Python
阿里面试Nacos配置中心交互模型是push还是pull原理解析
2022/07/23 Java/Android