图片
做者 | Uday Hiwarale
译者 | 王强
编辑 | Yonie
本文总结了 2019 年谷歌 I/O 大会上 Mathias 和 Sathya 提出来的 JavaScript 新规范功能。javascript
正则表达式(RegEx 或 正则表达式)在任何语言里都是强大的功能。在字符串中搜索复杂的模式时正则表达式就能大显身手了。以前 JavaScript 中的正则表达式实现已经很是齐全了,惟一缺乏的就是 lookbehind。html
首先咱们来了解一下正则表达式中的 lookahead 是什么含义,JavaScript 已经支持 lookahead 了。正则表达式中的 lookahead 语法容许你在字符串中选出的模式具备如下属性:另外一个已知模式正好紧靠这个模式或不与其相邻,或者在这个模式 以后。例如在字符串“MangoJuice,VanillaShake,GrapeJuice”中,咱们可使用正向 lookahead 语法来查找旁边有 Juice 的单词,即 Mango 和 Grape。
有两种类型的 lookahead,分别是正向 lookahead 和负向或否认的 lookahead。
正向 lookahead
正向 lookahead 选出的模式具备如下属性:另外一个已知模式位于选出模式以后。正向 lookahead 的语法以下。前端
/[a-zA-Z]+(?=Juice)/
上面的模式选出了大写或小写字母的单词,单词旁边都会有 Juice。不要把它和正则表达式中的捕获组混淆。Lookahead 和 Lookbehind 都是写在括号里的,但它们没有被捕获。下面看一个正向 lookahead 的实际例子。java
const testString = "MangoJuice, VanillaShake, GrapeJuice"; const testRegExp = /[a-zA-Z]+(?=Juice)/g; const matches = testString.match( testRegExp ); console.log( matches ); // ["Mango", "Grape"]
相似地,上面的例子中若是使用 负向 lookahead,就是选出全部后面没有 Juice 的单词。负向 lookahead 的语法与正向 lookahead 的语法相似,但有一处不一样。咱们须要把 = 符号换成! 符号。
/[a-zA-Z]+(?!Juice)/
上面的正向表达式模式会选出全部后面不跟着 Juice 的单词。但上面的模式会选出给定字符串中的全部单词,由于给定字符串中的全部单词都 不以 Juice 结尾,所以咱们须要更具体些的规则。web
/(Mango|Vanilla|Grape)(?!Juice)/
这种模式将选出 Mango、Vanilla 或 Grape 几个单词,它们后面没有跟着 Juice。来看具体的代码。正则表达式
const testString = "MangoJuice, VanillaShake, GrapeJuice"; const testRegExp= /(Mango|Vanilla|Grape)(?!Juice)/g; const matches = testString.match( testRegExp ); console.log( matches ); // ["Vanilla"]
与 lookahead 相似,Lookbehind 也是正则表达式中的一种语法,用它选出的模式具备如下属性:字符串中的某个已知模式位于或不在它的 前面。例如,在字符串“FrozenBananas,DriedApples,FrozenFish”中,咱们可使用正向 lookbehind 来找到前面有 Frozen 的单词,比好比 Bananas 和 Fish。
与 lookahead 相似,这里也有一个正向 lookbehind 和负向或否认 lookbehind。
正向 lookbehind
正向 lookbehind 选出的模式具备如下属性:另外一个已知模式位于它的前面。正向 lookbehind 的语法以下。算法
/(?<=Frozen)[a-zA-Z]+/
lookbehind 的模式相似于 lookahead,但带有额外的<符号,表示在前。上面的模式会选出全部以 Frozen 开头的单词或者在前面有 Frozen 的单词。来看具体的操做。编程
const testString = "FrozenBananas, DriedApples, FrozenFish"; const testRegExp = /(?<=Frozen)[a-zA-Z]+/g; const matches = testString.match( testRegExp ); console.log( matches ); // ["Bananas", "Fish"]
负向 lookbehind 选出的模式具备如下属性:另外一个已知模式不在它的前面。例如要选出“FrozenBananas,DriedApples,FrozenFish”字符串中前面没有 Frozen 的单词,咱们将使用如下语法。数组
/(?<!Frozen)[a-zA-Z]+/
但上面的模式将选出字符串中的全部单词,由于全部单词前面都没有 Frozen(FrozenBannanas 这样的单词这里会被视为一整个单词),咱们须要更具体一些。promise
/(?<!Frozen)(Bananas|Apples|Fish)/
写在代码中:
const testString = "FrozenBananas, DriedApples, FrozenFish"; const testRegExp = /(?<!Frozen)(Bananas|Apples|Fish)/g; const matches = testString.match( testRegExp ); console.log( matches ); // ["Apples"]
支持范围——TC39:阶段 4;Chrome:62+;Node:8.10.0+
类字段(class field) 是一种新的语法,用来从类构造函数外部定义实例(对象)的属性。有两种类型的类字段,公共类字段 和 私有类字段。
公共类字段
以前咱们必须在类构造函数中定义对象上的属性。这些属性是公共的,意味着能够在类(对象)的实例上访问它们。
class Dog { constructor() { this.name = 'Tommy'; } }
每当咱们有一个扩展父类的类时,必须先从构造函数中调用 super,而后才能在子类上添加属性,以下所述。
class Animal {} class Dog extends Animal { constructor() { super(); // call super before using `this` in constructor this.sound = 'Woof! Woof!'; } makeSound() { console.log( this.sound ); } } // create instance const tommy = new Dog(); tommy.makeSound(); // Woof! Woof!
如今有了公共类字段语法,咱们就能够在类的构造函数以外定义类字段,JavaScript 将隐式调用 super。
class Animal {} class Dog extends Animal { sound = 'Woof! Woof!'; // public class field makeSound() { console.log( this.sound ); } } // create instance const tommy = new Dog(); tommy.makeSound(); // Woof! Woof!
当 JavaScript 隐式调用 super 时,它会在实例化类时传递用户提供的全部参数(这是标准的 JavaScript 行为,与私有类字段无关)。所以,若是你的父构造函数须要定制参数,请确保手动调用 super。
class Animal { constructor( ...args ) { console.log( 'Animal args:', args ); } } class Dog extends Animal { sound = 'Woof! Woof!'; // public class field makeSound() { console.log( this.sound ); } } // create instance const tommy = new Dog( 'Tommy', 'Loves', 'Toys!' ); tommy.makeSound(); // Animal args: [ 'Tommy', 'Loves', 'Toys!' ]
支持范围——TC39:阶段 3;Chrome:72+;Node:12+
众所周知,JavaScript 没有 public、private 和 protected 之类的属性修饰符。默认状况下,对象上的全部属性都是公共的,这意味着任何人均可以访问它们。想要定义一个对外界隐藏的属性,最接近的方法是使用 Symbol 这个属性名称。你可能会使用 _ 前缀来表示应该是私有的属性,但它只是一种表示法,不能解决问题。
如今有了私有类字段,咱们可让类属性只能在类中访问,并防止它们反映在实例(对象)上。来看前面的一个例子,先看一个暴露的属性。
class Dog { _sound = 'Woof! Woof!'; // this is private makeSound() { console.log( this._sound ); } } // create instance const tommy = new Dog(); console.log( tommy._sound ); // Woof! Woof!
添加 _ 前缀并不能解决咱们的问题。私有类字段的定义方式与定义公共类字段的方式相同,但咱们没必要添加下划线前缀,而是添加 # 前缀。访问对象上的私有属性将致使 SyntaxError: Undefined private field。
class Dog { #sound = 'Woof! Woof!'; // this is private makeSound() { console.log( this.#sound ); } } // create instance const tommy = new Dog(); tommy.makeSound() // Woof! Woof! //console.log( tommy.#sound ); // SyntaxError
私有属性只能在定义它们的类中访问。所以在父类或子类内没法访问私有属性。
咱们还可使用未定义的值定义私有(和公共)属性。
class Dog { #name; constructor( name ) { this.#name = name; } showName() { console.log( this.#name ); } } // create instance const tommy = new Dog( 'Tommy' ); tommy.showName(); // Tommy
支持范围——TC39:阶段 3;Chrome:74+;Node:12+
咱们在 string 数据类型上有 match 原型方法,它根据给定的正则表达式或关键字返回字符串中的匹配模式。
const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /([A-Z0-9]+)/g; console.log( colors.match( matchColorRegExp ) ); // Output: ["EEE", "CCC", "FAFAFA", "F00", "000"]
但这种方法不提供其余附加信息,例如字符串中每一个匹配的索引。删除 g 标志后能够生成其余信息,但以后咱们只能得到第一个匹配项。
const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /#([A-Z0-9]+)/; console.log( colors.match( matchColorRegExp ) ); // Output: (result shortned for viewing purpose) ["#EEE", "EEE", index: 0, input: "<colors>"]
最后,咱们须要在正则表达式对象和语法上使用.exec 方法,这样写起来没那么复杂。咱们须要使用 while 循环,直到 exec 返回 null 为止。但要注意,exec 不会返回迭代器。
const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /#([A-Z0-9]+)/g; // in strict mode, // Uncaught ReferenceError: match is not defined while( match = matchColorRegExp.exec( colors ) ) { console.log( match ); } // Output: (result shortned for viewing purpose) ["#EEE", "EEE", index: 0, input: "<colors>"] ["#CCC", "CCC", index: 6, input: "<colors>"] ["#FAFAFA", "FAFAFA", index: 12, input: "<colors>"] ["#F00", "F00", index: 21, input: input: "<colors>"] ["#000", "000", index: 27, input: input: "<colors>"]
为了解决这个问题,咱们如今有了 matchAll 方法,它返回一个迭代器,而且这个迭代器的每次 next() 调用都会连续返回匹配的项。
const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /#([A-Z0-9]+)/g; console.log( ...colors.matchAll( matchColorRegExp ) ); // Output: (result shortned for viewing purpose) ["#EEE", "EEE", index: 0, input: "<colors>"] ["#CCC", "CCC", index: 6, input: "<colors>"] ["#FAFAFA", "FAFAFA", index: 12, input: "<colors>"] ["#F00", "F00", index: 21, input: input: "<colors>"] ["#000", "000", index: 27, input: input: "<colors>"]
支持范围——TC39:阶段 4;Chrome:73+;Firefox:67+;Node:12+
与其余语言相比,JavaScript 中捕获或捕获组的概念略有不一样。每当咱们在括号内放置一个正则表达式模式(lookahead 和 lookbehind 除外)时,它就会变成一个捕获组,全部匹配的模式都会反映在匹配的输出项中。
在前面的示例中,下面数组的第一项是正则表达式模式的完整匹配,而第二项是捕获组的匹配值。
["#EEE", "EEE", index: 0, input: "<colors>"]
若是有多个捕获组,它们将连续显示在结果中。咱们来看一个例子。
const str = "My name is John Doe."; const matchRegExp = /My name is ([a-z]+) ([a-z]+)/i; const result = str.match( matchRegExp );console.log( result ); // error, if result is null console.log( { firstName: result[1], lastName: result[2] } ); // Output: ["My name is John Doe", "John", "Doe", index: 0, input: "My name is John Doe.", groups: undefined] {firstName: "John", lastName: "Doe"}
如上所示,输出的第一个元素是完整匹配的字符串,而第二个和第三个元素是捕获组的结果。
如今有了命名捕获组后,咱们可使用标签将单个捕获组结果保存在
groups 对象中。定义命名捕获组的语法是 (?$pattern)。
const str = "My name is John Doe."; const matchRegExp = /My name is (?<firstName>[a-z]+) (?<lastName>[a-z]+)/i; const result = str.match( matchRegExp ); console.log( result ); console.log( result.groups ); // Output: ["My name is John Doe", "John", "Doe", index: 0, input: "My name is John Doe.", groups: {firstName: "John", lastName: "Doe"}] {firstName: "John", lastName: "Doe"}
命名捕获组也适用于 matchAll 方法。
支持范围——TC39:阶段 4;Chrome:64+;Node:10+
咱们写较大的整数或小数时,可读性一直是个大问题。例如,十亿写成数字是 1000000000,但你得数对零的个数才行,不少时候这都很让人头疼。
在较新版本的 JavaScript 中,咱们可使用 _ 分隔符来分隔数字的各个部分,以加强可读性
var billion = 1_000_000_000; console.log( billion ); // 1000000000
咱们能够随意将 _ 放在数字中,而 JavaScript 只会忽略它。这种方法适用于任何类型的数字,不管是整数、十进制、二进制、十六进制仍是八进制数字都行。
console.log( 1_000_000_000.11 ); // 1000000000.11 console.log( 1_000_000_000.1_012 ); // 1000000000.1012 console.log( 0xFF_00_FF ); // 16711935 console.log( 0b1001_0011 ); // 147 console.log( 0o11_17 ); // 591
支持范围——TC39:阶段 3;Chrome:75+;Node:12.5+
JavaScript 中的数字是从 Number 函数(也是构造函数)建立的。一个数字能够可靠表示的最大值是(2⁵³ - 1),也就是 9007199254740991。也可使用 Number.MAX_SAFE_INTEGER 生成这个数。
当咱们写下数字时,JavaScript 用 Number 构造函数包装它,以生成一个在其原型上包含数字方法的对象。全部原始数据类型都会这样处理。参阅 Primitives vs Objects 这篇 文章 来理解这个理念。
那么若是咱们继续加大这个数字会怎么样?
console.log( Number.MAX_SAFE_INTEGER ); // 9007199254740991 console.log( Number.MAX_SAFE_INTEGER + 10 ); // 9007199254741000
上面代码中的最后一个日志输出返回了错误的结果。发生这种状况是由于 JavaScript 没法计算超过 Number.MAX_SAFE_INTEGER 值的数字。
如今有了 BigInt 就能解决这个问题了。BigInt 能让咱们表示一个比 Number.MAX_SAFE_INTEGER 值更高的整数。与 Number 相似,BigInt 同时表现为一个函数和一个构造函数。加入 BigInt 后,JavaScript 有了新的 bigint 内置原始数据类型来表示大整数。
var large = BigInt( 9007199254740991 ); console.log( large ); // 9007199254740991n console.log( typeof large ); // bigint
JavaScript 会在整数的末尾添加 n 下标以表示 BigInt 整数形式。所以咱们只需在整数的最末尾附加 n 就能写成 BigInt 了。
如今咱们有了 BigInt,就能够安全地对具备 bigint 数据类型的大数字执行数学运算了。
var large = 9007199254740991n; console.log( large + 10n ); // 9007199254741001n
使用 number 数据类型的数字与使用 bigint 数据类型的数字不一样,由于 bigint 只能表示整数。所以程序不容许 bigint 和 number 数据类型之间的算术运算。
BigInt 函数能够接受任何类型的数字,如整数、二进制、十六进制、八进制等。它会在内部统一转换为十进制。
BigInt 还支持数字分隔符。
var large = 9_007_199_254_741_001n; console.log( large ); // 9007199254741001n
支持范围——TC39:阶段 3;Chrome:67+;Firefox:68+;Node:10.4+
数组对象上的 flat 和 flatMap 原型方法。
Array.flat
咱们如今能在一个数组使用一个新的 flat(n) 原型方法,它将数组展平到第 n 个深度并返回一个新数组。默认状况下 n 为 1。咱们能够将 n 做为 Infinity 传递,以展平全部嵌套数组。
var nums = [1, [2, [3, [4, 5]]]]; console.log( nums.flat() ); // [1, 2, [3, [4,5]]] console.log( nums.flat(2) ); // [1, 2, 3, [4,5]] console.log( nums.flat(Infinity) ); // [1, 2, 3, 4, 5]
支持范围——TC39:阶段 4;Chrome:69+;Firefox:62+;Node:12+
Array.flatMap
平常编程工做中有时可能会使用 map 变换数组,而后将其展平。例如计算一些整数的平方。
var nums = [1, 2, 3]; var squares = nums.map( n => [ n, n*n ] ) console.log( squares ); // [[1,1],[2,4],[3,9]] console.log( squares.flat() ); // [1, 1, 2, 4, 3, 9]
咱们可使用 flatMap 原型方法,用一个语法同时执行映射和展平。它只能将从回调函数返回的数组展平到 1 的深度。
var nums = [1, 2, 3]; var makeSquare = n => [ n, n*n ]; console.log( nums.flatMap( makeSquare ) ); // [1, 1, 2, 4, 3, 9]
支持范围——TC39:阶段 4;Chrome:69+;Firefox:62+;Node:11+
咱们可使用 对象 的 entries 静态方法提取对象的 key:value 对,该方法返回一个数组,其中每一个元素都是一个数组,后者的第一项是 key,第二项是 value。
var obj = {x:1,y:2,z:3}; var objEntries = Object.entries(obj); console.log(objEntries); // [[“x”,1],[“y”,2],[“z”,3]]
咱们如今能够在对象上使用 fromEntries 静态方法,它会将条目转换回对象。
var entries = [["x", 1],["y", 2],["z", 3]]; var obj = Object.fromEntries( entries ); console.log( obj ); // {x: 1, y: 2, z: 3}
以前咱们使用 entries 就能很容易地过滤和映射对象值,但将条目放回到对象表单却很麻烦。这里就可使用 fromEntries 简化工做了。
var obj = { x: 1, y: 2, z: 3 }; // [["x", 1],["y", 2],["z", 3]] var objEntries = Object.entries( obj ); // [["x", 1],["z", 3]] var filtered = objEntries.filter( ( [key, value] ) => value % 2 !== 0 // select odd ); console.log( Object.fromEntries( filtered ) ); // {x: 1, z: 3}
当咱们使用 Map 按插入顺序存储键值对时,内部数据结构与条目格式相似。咱们可使用 fromEntries 轻松地从 Map 构造一个对象。
var m = new Map([[“x”,1],[“y”,2],[“z”,3]]); console.log(m); // {“x”=> 1,“y”=> 2,“z”=> 3} console.log(Object.fromEntries(m)); // {x:1,y:2,z:3}
支持范围——TC39:阶段 4;Chrome:73+;Firefox:63+;Node:12+
以前咱们很熟悉 JavaScript 中的 this 关键字。它没有肯定的值,其值取决于访问它的上下文。在任何环境中,当从程序的最顶层上下文访问时 this 指向全局对象,这就是所谓的全局 this。
例如,在 JavaScript 中全局 this 是 window 对象,你能够在 JavaScript 文件的顶部(最外层上下文)或 JavaScript 控制台内添加 console.log(this) 语句来验证这一点。
图片
this 全局值在 Node.js 内部会指向 global 对象,而在 web worker 内部会指向 web worker 自己。可是要获取全局 this 值不太容易,由于咱们不能在全部位置使用 this 关键字;例如,在类构造函数中 this 值指向类实例。
所以其余环境为咱们提供了像 self 这样的关键字,与 JavaScript 和 web worker 中的全局 this 同样;而在 Node.js 中使用的是 global。使用这些替代关键字时,咱们能够建立一个通用函数来返回全局 this 值。
const getGlobalThis = () => { if (typeof self !== 'undefined') return self; if (typeof window !== 'undefined') return window; if (typeof global !== 'undefined') return global; if (typeof this !== 'undefined') return this; throw new Error('Unable to locate global `this`'); }; var globalThis = getGlobalThis();
可是用这个 polyfill 获取全局 this 对象会出问题,这篇文章解释了缘由: https://mathiasbynens.be/notes/globalthis。为了解决这个问题,JavaScript 如今提供了 globalThis 关键字,它能够从任何地方返回全局 this 对象。
var obj = { fn: function() { console.log( 'this', this === obj ); // true console.log( 'globalThis', globalThis === window ); // true } }; obj.fn();
支持范围——TC39:阶段 3;Chrome:71+;Firefox:65+;Node:12+
咱们对数组排序时,ECMAScript 不会为 JavaScript 引擎提出排序算法,而只会强制执行排序 API 的语法。所以排序性能和 / 或排序稳定性会随着浏览器或 JavaScript 引擎的不一样而变化。
但如今 ECMAScript 强制数组排序算法保持稳定。这个答案介绍了排序稳定性更新: https://stackoverflow.com/a/1517824
简而言之,若是排序结果(变异数组)中那些不受排序影响的项目顺序不变,与一开始插入的顺序一致,则排序算法就是稳定的。咱们来看一个例子吧。
var list = [ { name: 'Anna', age: 21 }, { name: 'Barbra', age: 25 }, { name: 'Zoe', age: 18 }, { name: 'Natasha', age: 25 } ]; // possible result [ { name: 'Natasha', age: 25 } { name: 'Barbra', age: 25 }, { name: 'Anna', age: 21 }, { name: 'Zoe', age: 18 }, ]
如上所示,在 list 数组中,名为 Barbra 的对象位于名为 Natasha 的对象以前。因为这些对象有着相同的年龄,咱们但愿排序结果中它们保持相同的顺序,但有时结果并不是如此。排序算法的结果会取决于你使用的 JavaScript 引擎。
可是如今,全部现代浏览器和 Node.js 默认使用 sort 方法进行稳定排序。这将始终产生如下结果。
// stable sort result [ { name: 'Barbra', age: 25 }, { name: 'Natasha', age: 25 } { name: 'Anna', age: 21 }, { name: 'Zoe', age: 18 }, ]
一些 JavaScript 引擎之前支持稳定排序,但仅适用于较小的数组。为了提升大型数组的性能,他们可能会使用更快的算法并牺牲排序稳定性。
支持范围——Chrome:70+;Firefox:62+;Node:12+
国际化 API 是由 JavaScript 中的 ECMAScript 标准提供的 API,用于格式化指定语言中的数字、字符串、日期和时间。此 API 在 Intl 对象上可用。此对象提供构造函数,以便为指定的区域设置建立与区域相关数据的格式化程序。可在 此处查看支持的区域设置列表: http://www.lingoes.net/en/translator/langcode.html
Intl.RelativeTimeFormat
在许多应用程序中,咱们一般须要以相对格式显示时间,例如 5 分钟前、昨天、1 周前 等。当咱们的网站须要区分不一样区域的显示内容时,咱们须要在分发包中存放全部可能的相对时间输出组合 。
JavaScript 如今在 Intl 对象上提供了 RelativeTimeFormat9(locale, config) 构造函数,它容许你为特定的区域设置建立时间格式化程序。这将建立一个具备 format(value, unit) 原型方法的对象来生成时间格式。
// español (spanish) var rtfEspanol= new Intl.RelativeTimeFormat('es', { numeric: 'auto' }); log( rtfEspanol.format( 5, 'day' ) ); // dentro de 5 días log( rtfEspanol.format( -5, 'day' ) ); // hace 5 días log( rtfEspanol.format( 15, 'minute' ) ); // dentro de 15 minutos
支持范围——TC39:阶段 3;Chrome:71+;Firefox:65+;Node:12+
Intl.ListFormat
ListFormat API 容许咱们将列表中的项目基于 and 或 or 格式组合在一块儿。例如,[apples,mangoes,bananas] 使用并列格式就是 apples,mangoes and bananas,使用分离格式就是 apples,mangoes or bananas。
首先,咱们须要根据区域环境从 ListFormat(locale, config) 构造函数建立格式化程序实例,并使用 format(list) 原型方法生成特定于区域环境的列表格式。
// español (spanish) var lfEspanol = new Intl.ListFormat('es', { type: 'disjunction' }); var list = [ 'manzanas', 'mangos', 'plátanos' ]; log( lfEspanol.format( list ) ); // manzanas, mangos o plátanos
支持范围——TC39:阶段 3;Chrome:72+;Node:12+
除了语种名称外,区域设置一般还有不少内容,如日历类型、小时制、语言等。Intl.Locale(localeId, config) 构造函数用来基于提供的配置生成格式化的语言环境字符串。它建立的对象包含全部区域设置属性,并暴露 toString 原型方法以获取格式化的区域设置字符串。
const krLocale = new Intl.Locale( 'ko', { script: 'Kore', region: 'KR', hourCycle: 'h12', calendar: 'gregory' } ); log( krLocale.baseName ); // ko-Kore-KR log( krLocale.toString() ); // ko-Kore-KR-u-ca-gregory-hc-h12
在此处了解区域设置标识符和 Unicode 区域设置标记:https://unicode.org/reports/tr35/#unicode_locale_id
支持范围——TC39:阶段 3;Chrome:74+;Node:12+
以前,咱们在 Promise 构造函数上有 all 和 race 两种静态方法。Promise.all([... promises]) 返回一个 promise,它在输入的全部promises 解析后才解析,输入的任何promise 被拒绝时它也会被拒绝。Promise.race([... promises]) 返回一个 promise,输入的任何 promise 解析后它就会解析,输入的任何 promise 被拒绝后它也会被拒绝。
咱们迫切须要一个静态方法来返回一个 promise,它要在全部 promise 完成后(解析或拒绝)解析。咱们还须要一个相似 race 的方法来返回一个 promise,等输入的任何 promise 解析后它就会解析。
Promise.allSettled
Promise.allSettled 方法获取一组 promise,并在全部 promise 都被解析或拒绝后解析。所以,此方法返回的 promise 不须要 catch 回调,由于它老是会解析。then 回调按照各个 promise 的顺序接收每一个 promise 的 status 和 value。
var p1 = () => new Promise( (resolve, reject) => setTimeout( () => resolve( 'val1' ), 2000 ) ); var p2 = () => new Promise( (resolve, reject) => setTimeout( () => resolve( 'val2' ), 2000 ) ); var p3 = () => new Promise( (resolve, reject) => setTimeout( () => reject( 'err3' ), 2000 ) ); var p = Promise.allSettled( [p1(), p2(), p3()] ).then( ( values ) => console.log( values ) ); // Output [ {status: "fulfilled", value: "val1"} {status: "fulfilled", value: "val2"} {status: "rejected", value: "err3"} ]
支持范围——TC39:阶段 3;Chrome:76+
Promise.any 方法相似于 Promise.race,可是只要任何 promise 被拒绝,后者返回的 promise 就不会执行 catch 块。相比之下,前者等任何 promise 解析后它返回的 promise 也会解析。若是没有解析任何 promise,catch 块将被执行。若是有任何 promise 先解析了,就会执行 then 块。
支持范围——TC39:阶段 1
观看本文视频: https://www.youtube.com/watch?v=c0oy0vQKEZE
英文原文: https://itnext.io/whats-new-in-javascript-google-i-o-2019-summary-d16bd230841活动推荐前端人必备的《浏览器工做原理与实践》上线了!7 大模块,覆盖性能优化、页面渲染、JS、浏览器安全等内容,带你全方位搞懂浏览器原理。扫码看做者李兵,也算是浏览器领域的大牛了,08 年他就基于 Chromium 和 IE 发布了一款双核浏览器:太阳花,是国内第一款双核浏览器。