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 相关文章推荐
this[] 指的是什么内容 讨论
Mar 24 Javascript
驱动事件的addEvent.js代码
Mar 27 Javascript
用javascript将数据库中的TEXT类型数据动态赋值到TEXTAREA中
Apr 20 Javascript
jsp网页搜索结果中实现选中一行使其高亮
Feb 17 Javascript
js调试系列 源码定位与调试[基础篇]
Jun 18 Javascript
Fullpage.js固定导航栏-实现定位导航栏
Mar 17 Javascript
原生js的数组除重复简单实例
May 24 Javascript
浅谈js多维数组和hash数组定义和使用
Jul 27 Javascript
JS动态计算移动端rem的解决方案
Oct 14 Javascript
jQuery中layer分页器的使用
Mar 13 Javascript
微信公众号开发之微信支付代码记录的实现
Oct 16 Javascript
Vue中axios拦截器如何单独配置token
Dec 27 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上传图片存入数据库示例分享
2014/03/11 PHP
PHP上传图片、删除图片简单实例
2016/11/12 PHP
关于B/S判断浏览器断开的问题讨论
2008/10/29 Javascript
javascript中的new使用
2010/03/20 Javascript
javascript 用函数语句和表达式定义函数的区别详解
2014/01/06 Javascript
JQuery右键菜单插件ContextMenu使用指南
2014/12/19 Javascript
js与jquery回车提交的方法
2015/02/03 Javascript
元素绑定click点击事件方法
2015/06/08 Javascript
jquery中的工具使用方法$.isFunction, $.isArray(), $.isWindow()
2015/08/09 Javascript
JavaScript 实现的 zip 压缩和解压缩工具包Zip.js使用详解
2015/12/14 Javascript
jQuery Mobile弹出窗、弹出层知识汇总
2016/01/05 Javascript
JavaScript设计模式经典之命令模式
2016/02/24 Javascript
js设置文字颜色的方法示例
2016/12/30 Javascript
JQuery Ajax 异步操作之动态添加节点功能
2017/05/24 jQuery
JavaScript条件判断_动力节点Java学院整理
2017/06/26 Javascript
vue2.0项目中使用Ueditor富文本编辑器示例代码
2017/08/14 Javascript
原生javascript实现的全屏滚动功能示例
2017/09/19 Javascript
JS路由跳转的简单实现代码
2017/09/21 Javascript
vue通过点击事件读取音频文件的方法
2018/05/30 Javascript
js中apply()和call()的区别与用法实例分析
2018/08/14 Javascript
微信小程序实现同一页面取值的方法分析
2019/04/30 Javascript
python继承和抽象类的实现方法
2015/01/14 Python
Python安装使用命令行交互模块pexpect的基础教程
2016/05/12 Python
在Python中调用Ping命令,批量IP的方法
2019/01/26 Python
解决Django中调用keras的模型出现的问题
2019/08/07 Python
解决python3 requests headers参数不能有中文的问题
2019/08/21 Python
PythonPC客户端自动化实现原理(pywinauto)
2020/05/28 Python
html5定制表单_动力节点Java学院整理
2017/07/11 HTML / CSS
美国摄影爱好者购物网站:Focus Camera
2016/10/21 全球购物
Carolina工作鞋官网:Carolina Footwear
2019/03/14 全球购物
海量信息软件测试笔试题
2015/08/08 面试题
文科生自我鉴定
2014/02/15 职场文书
爱护花草树木的标语
2014/06/11 职场文书
导游词之山东八大关
2019/12/18 职场文书
Windows下载并安装MySQL8.0.x 版本的完整教程
2022/04/10 MySQL
nginx location 带斜杠【 / 】与不带的区别
2022/04/13 Servers