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 相关文章推荐
8款非常棒的响应式jQuery 幻灯片插件推荐
Feb 02 Javascript
jquery选择器大全 全面详解jquery选择器
Mar 06 Javascript
JAVA四种基本排序方法实例总结
Jul 24 Javascript
jquery实现表单验证简单实例演示
Nov 23 Javascript
Jquery uploadify上传插件使用详解
Jan 13 Javascript
如何将 jQuery 从你的 Bootstrap 项目中移除(取而代之使用Vue.js)
Jul 17 jQuery
深入理解React高阶组件
Sep 28 Javascript
Javascript实现动态时钟效果
Nov 17 Javascript
使用NestJS开发Node.js应用的方法
Dec 03 Javascript
VuePress 静态网站生成方法步骤
Feb 14 Javascript
javascript验证form表单数据的案例详解
Mar 25 Javascript
angularjs自定义过滤器demo示例
Aug 24 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
xss防御之php利用httponly防xss攻击
2014/03/21 PHP
CI框架中libraries,helpers,hooks文件夹详细说明
2014/06/10 PHP
PHP函数rtrim()使用中的怪异现象分析
2017/02/24 PHP
Avengerls vs Newbee BO3 第一场2.18
2021/03/10 DOTA
用javascript实现分割提取页面所需内容
2007/05/09 Javascript
使用POST方式弹出窗口的两种方法示例介绍
2014/01/29 Javascript
如何实现移动端浏览器不显示 pc 端的广告
2015/10/15 Javascript
Node.js重新刷新session过期时间的方法
2016/02/04 Javascript
js利用appendChild对标签进行排序的实现方法
2016/10/16 Javascript
jQuery动态创建元素以及追加节点的实现方法
2016/10/20 Javascript
jQuery中layer分页器的使用
2017/03/13 Javascript
Vue中的v-cloak使用解读
2017/03/27 Javascript
Vee-Validate的使用方法详解
2017/09/22 Javascript
详解JSON Web Token 入门教程
2018/07/30 Javascript
vue2.0实现的tab标签切换效果(内容可自定义)示例
2019/02/11 Javascript
ES6中Set和Map用法实例详解
2020/03/02 Javascript
[03:43]TI9战队采访——PSG.LGD
2019/08/22 DOTA
python中 ? : 三元表达式的使用介绍
2013/10/09 Python
python实现的udp协议Server和Client代码实例
2014/06/04 Python
python中OrderedDict的使用方法详解
2017/05/05 Python
python中Matplotlib实现绘制3D图的示例代码
2017/09/04 Python
Django权限机制实现代码详解
2018/02/05 Python
Python 解决中文写入Excel时抛异常的问题
2018/05/03 Python
Python 3.8中实现functools.cached_property功能
2019/05/29 Python
使用 PyTorch 实现 MLP 并在 MNIST 数据集上验证方式
2020/01/08 Python
python函数定义和调用过程详解
2020/02/09 Python
pycharm专业版远程登录服务器的详细教程
2020/09/15 Python
水上运动奥特莱斯:Wasterports Outlet
2018/08/08 全球购物
高级3D打印市场:Gambody
2019/12/26 全球购物
生物科学专业个人求职信范文
2013/12/07 职场文书
结婚典礼证婚词
2014/01/11 职场文书
《穷人》教学反思
2014/04/08 职场文书
2014年幼儿园教师工作总结
2014/11/08 职场文书
采购员岗位职责
2015/02/03 职场文书
2019年度政务公开考核工作总结模板
2019/11/11 职场文书
Java 泛型详解(超详细的java泛型方法解析)
2021/07/02 Java/Android