ES6-ES12
ES6新特性
1.let变量
2.const常量
3.变量的解构赋值【数组解构赋值和对象解构赋值
4.模板字符串
5.对象的简写
const school = {
name,
change,
improve() {
console.log('llllllaallalal');
}
}
6.箭头函数
7.rest参数
8.扩展运算符(数组)
9.Symbol
10.迭代器
11.生成器函数
12.Promise
13.集合Set
14.字典Map
15.class类
16.Number的扩展
1.Number.EPSILON 是 JavaScript 表示的最小精度
// EPSILON属性的值接近于 2.220446049250313e-16
// function equal(a, b) {
// if (Math.abs(a-b) < Number.EPSILON) {
// return true
// } else {
// return false
// }
// }
// console.log(Number.EPSILON);
// console.log(0.1+0.2===0.3); // false
// console.log(equal(0.1+0.2, 0.3)); // true
// 2.二进制和八进制
let b = 0b1010; // 二进制 2**3 + 2**1 = 10
// console.log(b);
// console.log(3**3); // 3**3标识3的三次方
let o = 0o777; // 八进制 7*(8**2) + 7*(8**1) + 7*(8**0) = 511
// console.log(o);
let d = 100 // 十进制 100
let x = 0xff; // 15*16**1+15*16**0 = 255
// console.log(x);
// 3.Number.isFinite 检测一个数值是否为有限数
// console.log(Number.isFinite(100)); // true
// console.log(Number.isFinite(100/0)); // false
// console.log(Number.isFinite(Infinity)); // false
// 4.Number.parseInt Number.parseFloat字符串转整数
// console.log(Number.parseInt('134134love')); // 134134
// console.log(Number.parseFloat('3.1415926神级')); // 3.1415926
// console.log(Number.parseInt('aaa134134love')) // NaN
// console.log(Number.parseFloat('ooo3.1415926神级')) // NaN
// 5.Number.isInteger 判断一个数是否为整数
// console.log(Number.isInteger(5)); // true
// console.log(Number.isInteger(2.5)); // false
// 6.Math.trunc 将数字的小数部分抹掉
// console.log(Math.trunc(3.5)); // 3
// 7.Math.sign 判断一个数到底是正数 负数 还是零
console.log(Math.sign(100)); // 1
console.log(Math.sign(0)); // 0
console.log(Math.sign(-20000)); // -1
17.对象方法Object的扩展
// 1.Object.is 判断两个值是否完全相等
// console.log(Object.is(1,1)); // true
// console.log(Object.is(NaN,NaN)); // true
// console.log(Object.is({},{})); // false
// console.log(NaN === NaN); // false
// 2.Object.assign 对象的合并
// const obj1 = {
// name: 'M',
// age: 19
// }
// const obj2 = {
// name: 'T'
// }
// console.log(Object.assign({}, obj1, obj2)); //{ name: 'T', age: 19 }
// 3.Object.setPrototypeOf Object.getPrototypeOf
const school = {
name: '加大'
}
const cities = {
xiaoqu: ['俄罗斯', '美国']
}
Object.setPrototypeOf(school, cities) // 将cities设置成为 school的原型
console.log(Object.getPrototypeOf(school)); // 获取school的原型对象内容
console.log(school);
18.浏览器使用ES6模块化引入
<script type="module">
/*
在浏览器中也可以使用JavaScript modules(模块功能)了。目前支持这一特性的浏览器包括:
Safari 10.1.
谷歌浏览器(Canary 60) – 需要在chrome:flags里开启”实验性网络平台功能(Experimental Web Platform)”
Firefox 54 – 需要在about:config里开启dom.moduleScripts.enabled选项。
Edge 15 – 需要在about:flags里开启 Experimental JavaScript Features 选项
需要将静态文件部署到服务器就能正常访问
*/
import * as m1 from './m1.js'
console.log(globalThis);
console.log(m1);
</script>
19.模块化数据语法汇总
<!-- 浏览器使用模块化方式一 -->
<script type="module">
/*
在浏览器中也可以使用JavaScript modules(模块功能)了。目前支持这一特性的浏览器包括:
Safari 10.1.
谷歌浏览器(Canary 60) – 需要在chrome:flags里开启”实验性网络平台功能(Experimental Web Platform)”
Firefox 54 – 需要在about:config里开启dom.moduleScripts.enabled选项。
Edge 15 – 需要在about:flags里开启 Experimental JavaScript Features 选项
需要将静态文件部署到服务器就能正常访问
*/
// 1.通用的导入方式
// import * as m1 from './m1.js'
// import * as m2 from './m2.js'
// import * as m3 from './m3.js'
// console.log(globalThis);
// console.log(m1);
// console.log(m3);
// console.log(m2.default);
// 2.结构赋值形式
// import {school, teach} from './m3.js'
// import {school as newName, teach} from './m3.js'
// import {default as m2} from './m2.js'
// console.log(newName, teach());
// console.log(m2);
// 3.简便形式 针对默认暴露
// import m2 from './m2.js'
// console.log(m2);
</script>
<!-- 浏览器使用模块化方式二 -->
<script src="./app.js" type="module"></script>
20.babel对ES6模块化代码转化
<!--
1.安装工具 babel-cli babel-preset-env browserify或(webpack)
1)npm init
2)cnpm install --save-dev @babel/core @babel/cli @babel/preset-env browserify
https://www.babeljs.cn/
https://github.com/browserify/browserify
3)npx babel js --out-dir dist
4)打包 npx browserify dist/app.js -o dist/bundle.js
ES6转ES5后文件夹dist也是不能直接运行的需要打包
报错Uncaught ReferenceError: require is not defined at app.js:3:1
********************************************
在 npm version >= 5.2.0 开始,自动安装了npx。
npx是什么呢? npx 会帮你执行依赖包里的二进制文件。
举个例子:
npm i webpack -D //非全局安装
//如果要执行 webpack 的命令
./node_modules/.bin/webpack -v
有了 npx 之后
npm i webpack -D //非全局安装
npx webpack -v
npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到,就会帮你安装。
参考文章:https://www.jianshu.com/p/684329089d06
***********************************************
-->
<script src="./dist/bundle.js"></script>
ES7新特性
1.Array.prototype.includes
/*
1.Array.prototype.includes
includes 方法用来检测数组中是否包含某个元素,返回布尔值
*/
const persons = ['张飞', '关羽', '赵云']
// console.log(persons.includes('张飞')); // true
// console.log(persons.includes('诸葛亮')); // false
/*
2.指数操作符
2.指数操作符
在ES7中引入指数运算符 [**], 用来实现幂运算,功能与Math.pow 结果相同
*/
// console.log(2**4); // 16
// console.log(2**4 === Math.pow(2, 4)); // true
ES8新特性
1.async函数
2.await表达式
3.对象的扩展方法
Object.keys(school)
Object.values(school)
Object.entries(school)
Object.getOwnPropertyDescriptors(school)
const obj = Object.create(null, {
name: {
value: '北大',
writable: true, // 是否可以重新赋值
configurable: true, // 是否可以删除
enumerable: true // 是否可以枚举
},
age: {}
})
4.String.prototype.padStart
把指定字符串填充到字符串头部,返回新字符串。
语法 str.padStart(targetLength [, padString])
-
targetLength
当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。
-
padString可选填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的默认值为 " "
示例
'abc'.padStart(10); // " abc" 'abc'.padStart(10, "foo"); // "foofoofabc" 'abc'.padStart(6,"123465"); // "123abc" 'abc'.padStart(8, "0"); // "00000abc" 'abc'.padStart(1); // "abc"应用场景
日期格式化:yyyy-mm-dd的格式:
const now = new Date() const year = now.getFullYear() // 月份和日期 如果是一位前面给它填充一个0 const month = (now.getMonth() + 1).toString().padStart(2, '0') const day = (now.getDate()).toString().padStart(2, '0') console.log(year, month, day) console.log( `${year}-${month}-${day}` ) //输入今天的日期 2021-12-31数字替换(手机号,银行卡号等)
const tel = '18781268679' const newTel = tel.slice(-4).padStart(tel.length, '*') console.log(newTel) // *******8679
5.String.prototype.padEnd
把指定字符串填充到字符串尾部,返回新字符串。
语法 str.padStart(targetLength [, padString])
-
targetLength
当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。
-
padString可选填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的默认值为 " "
示例
'abc'.padEnd(10); // "abc " 'abc'.padEnd(10, "foo"); // "abcfoofoof" 'abc'.padEnd(6, "123456"); // "abc123" 'abc'.padEnd(1); // "abc"应用场景
在JS前端我们处理时间戳的时候单位是ms毫秒,但是,后端同学返回的时间戳则不一样是毫秒,可能只有10位,以s秒为单位。所以,我们在前端处理这个时间戳的时候,保险起见,要先做一个13位的补全,保证单位是毫秒。
// 伪代码 console.log(new Date().getTime()) // 时间戳 13位的 timestamp = +String(timestamp).padEnd(13, '0')
ES9新特性
1.扩展运算符与rest参数
Rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过ES6中只针对于数组。
在 ES9 中为对象提供了像数组一样的 rest 参数和扩展运算符
2.正则扩展-命名捕获分组
let str = '<a href="https://www.baidu.com">百度一下</a>';
// 提取 URL 与 【标签文本】
// const reg = /<a href="(.*)">(.*)<\/a>/
// 执行
// const result = reg.exec(str);
// console.log(result);
// console.log(result[0]);
// console.log(result[1]);
// 分组命名 添加 ?<url> 就会在group形成分组
const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/
const result = reg.exec(str);
console.log(result);
3.正则扩展-反向断言
let str = 'jalsdfjlasf2234234你考虑撒就订饭了8888理解啊东风路卡啦啦啦'
// 正向断言 提取8888
// const reg = /\d+(?=理解)/; // ?= 固定写法
// const result = reg.exec(str)
// console.log(result);
// 反向断言 提取8888
const reg = /(?<=订饭了)\d+/ // ?<= 固定写法
const result = reg.exec(str);
console.log(result);
4.正则扩展-doAll模式
let str = `
<ul>
<li>
<a>肖生克的救赎</a>
<p>上映时间:1994-09-10</p>
</li>
<li>
<a>阿甘正传</a>
<p>上映时间:1994-07-06</p>
</li>
</ul>
`
// 声明正则
// const reg = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>\s+<\/li>/g;
const reg = /<li>(.*?)<a>(.*?)<\/a>(.*?)<p>(.*?)<\/p>(.*?)<\/li>/gs; // dotAll模式
// const result = reg.exec(str)
// console.log(result);
let result;
let data = [];
while(result = reg.exec(str)) {
console.log(result);
data.push({title: result[1], time: result[2]})
}
5.for await of
异步迭代器(for-await-of):循环等待每个Promise对象变为resolved状态才进入下一步。
我们知道 for...of 是同步运行的,看如下代码
function TimeOut(time){
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(time)
}, time)
})
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]
for (let item of arr) {
console.log(Date.now(),item.then(console.log))
}
}
test()
上面打印结果如下图

上述代码证实了 for of 方法不能遍历异步迭代器,得到的结果并不是我们所期待的,于是 for await of 就粉墨登场啦!
ES9 中可以用 for...await...of 的语法来操作
function TimeOut(time) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(time)
}, time)
})
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]
for await (let item of arr) {
console.log(Date.now(), item)
}
}
test()

for await of 环等待每个Promise对象变为resolved状态才进入下一步。所有打印的结果为 2000,1000,3000
6.Promise.prototype.finally()
Promise.prototype.finally() 方法返回一个Promise,在promise执行结束时,无论结果是fulfilled或者是rejected,在执行then()和catch()后,都会执行finally指定的回调函数。这为指定执行完promise后,无论结果是fulfilled还是rejected都需要执行的代码提供了一种方式,避免同样的语句需要在then()和catch()中各写一次的情况。
示例
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
// reject('fail')
}, 1000)
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
}).finally(() => {
console.log('finally')
})
使用场景
需要每次发送请求,都会有loading提示,请求发送完毕,就需要关闭loading提示框,不然界面就无法被点击。不管请求成功或是失败,这个loading都需要关闭掉,这时把关闭loading的代码写在finally里再合适不过了
ES10新特性
1.对象方法拓展Object.fromEntries
// Object.fromEntries 是 Object.Entries的逆运算
// Object.Entries将对象生成二位数组
// Object.fromEntries将二维数组转换成对象
// 二维数组
const result = Object.fromEntries([
['name', 'M'],
['age', 78]
])
// console.log(result); // {name: 'M', age: 78}
// Map
const m = new Map()
m.set('name', 'T')
// console.log(Object.fromEntries(m)); // {name: 'T'}
// Object.entries ES8
const arr = Object.entries({
name: 'L'
})
console.log(arr);
console.log(Object.fromEntries(arr));
案例1:Object 转换操作
const obj = {
name: 'jimmy',
age: 18
}
const entries = Object.entries(obj)
console.log(entries)
// [Array(2), Array(2)]
// ES10
const fromEntries = Object.fromEntries(entries)
console.log(fromEntries)
// {name: "jimmy", age: 18}
案例2:Map 转 Object
const map = new Map()
map.set('name', 'jimmy')
map.set('age', 18)
console.log(map) // {'name' => 'jimmy', 'age' => 18}
const obj = Object.fromEntries(map)
console.log(obj)
// {name: "jimmy", age: 18}
案例3:过滤
course表示所有课程,想请求课程分数大于80的课程组成的对象:
const course = {
math: 80,
english: 85,
chinese: 90
}
const res = Object.entries(course).filter(([key, val]) => val > 80)
console.log(res) // [ [ 'english', 85 ], [ 'chinese', 90 ] ]
console.log(Object.fromEntries(res)) // { english: 85, chinese: 90 }
案例4:url的search参数转换
// let url = "https://www.baidu.com?name=jimmy&age=18&height=1.88"
// queryString 为 window.location.search
const queryString = "?name=jimmy&age=18&height=1.88";
const queryParams = new URLSearchParams(queryString);
const paramObj = Object.fromEntries(queryParams);
console.log(paramObj); // { name: 'jimmy', age: '18', height: '1.88' }
2.字符串方法扩展-trimStart-trimEnd
let str = ' iloveyou ';
console.log(str);
console.log(str.trimStart());
console.log(str.trimEnd());
3.数组方法扩展-flat与flatMap
// 1.flag 平 参数默认是 铺平1层
// const arr = [1,2,3,4,5,[6,7,8]]
// console.log(arr.flat());
// const arr = [1,2,3,4,5,[6,7,8,[9,10]]]
// console.log(arr.flat(2))
// 2.flatMap 是flat 和 Map组合
const arr = [1,2,3,4];
const result = arr.flatMap(item => [item * 10]);
console.log(result);
4.Symbol.prototype.description
我们知道,Symbol 的描述只被存储在内部的 Description ,没有直接对外暴露,我们只有调用 Symbol 的 toString() 时才可以读取这个属性:
const name = Symbol('es')
console.log(name.toString()) // Symbol(es)
console.log(name) // Symbol(es)
console.log(name === 'Symbol(es)') // false
console.log(name.toString() === 'Symbol(es)') // true
现在可以通过 description 方法获取 Symbol 的描述:
const name = Symbol('es')
console.log(name.description) // es
name.description = "es2" // 只读属性 并不能修改描述符
console.log(name.description === 'es') // true
// 如果没有描述符 输入undefined
const s2 = Symbol()
console.log(s2.description) // undefined
5.修订 Function.prototype.toString()
以前函数的toString方法来自Object.prototype.toString(),现在的 Function.prototype.toString() 方法返回一个表示当前函数源代码的字符串。以前只会返回这个函数,不包含注释、空格等。
function foo() {
// es10新特性
console.log('imooc')
}
console.log(foo.toString())
// 打印如下
// function foo() {
// // es10新特性
// console.log("imooc");
// }
ES11新特性
1.私有属性
class Person {
// 公有属性
name = 'M';
// 私有属性
#age = 19;
#weight;
// 构造方法
constructor(name, age, weight) {
this.#weight = weight
}
}
const girl = new Person('M', 19, '50kg')
console.log(girl.name);
// console.log(girl.#age);
// console.log(girl.#weight);
2.Promise.allSettled
/*
Promise.all 全部成功才成功 有一个失败都返回失败
Promise.allSettled 无论失败还是成功都返回成功状态
*/
const p1 = new Promise((res, rej) => {
setTimeout(() => {
res('商品数量 - 1')
}, 1000);
})
const p2 = new Promise((res, rej) => {
setTimeout(() => {
// res('商品数量 - 2')
rej('商品2出错了')
}, 1000);
})
// 调用 allsettled 方法
const result = Promise.allSettled([p1, p2]);
console.log(result);
//
const res = Promise.all([p1, p2]);
console.log(res);
3.String.protorype.matchAll方法
let str = `
<ul>
<li>
<a>肖生克的救赎</a>
<p>上映时间:1994-09-10</p>
</li>
<li>
<a>阿甘正传</a>
<p>上映时间:1994-07-06</p>
</li>
</ul>
`
// 声明正则
const reg = /<li>(.*?)<a>(.*?)<\/a>(.*?)<p>(.*?)<\/p>(.*?)<\/li>/gs; // dotAll模式
const result = str.matchAll(reg);
console.log(result);
for (const iterator of result) {
console.log(iterator);
}
4.可选链操作符
// ?.
function main(config) {
const dbHost = config?.db?.host;
console.log(dbHost);
}
main({
db: {
host: '192.168.1.1',
username: 'M'
}
})
5.bigInt类型
// 大整形
// let n = 512n
// 大整形只能和大整形运算
// console.log(123n + 1n);
// console.log(n, typeof(n)); // 512n bigint
// 函数
// let n = 123;
// console.log(BigInt(n));
// console.log(BigInt(1.2)); // 报错
// 大数值运算
let max = Number.MAX_SAFE_INTEGER;
console.log(max); // 9007199254740991
console.log(max + 1); // 9007199254740992
console.log(max + 2); // 9007199254740992 加几都返回 9007199254740992\
console.log(BigInt(max));
// 大整形只能和大整形运算
console.log(BigInt(max) + BigInt(1));
// 大整形只能和大整形运算
console.log(BigInt(max) + BigInt(8));
6.import动态引入
const btn = document.querySelector('#btn');
btn.onclick = function () {
// 动态引入
import('./m1.js').then(module => {
console.log(module);
module.teach()
})
}
7.绝对全局对象globalThis
console.log(globalThis); // 在nodejs环境是global 在window环境是window
8.空值合并运算符(Nullish coalescing Operator)
空值合并操作符( ?? )是一个逻辑操作符,当左侧的操作数为 null或者undefined时,返回其右侧操作数,否则返回左侧操作数。
const foo = undefined ?? "foo"
const bar = null ?? "bar"
console.log(foo) // foo
console.log(bar) // bar
复制代码
与逻辑或操作符(||)不同,逻辑或操作符会在左侧操作数为假值时返回右侧操作数。也就是说,如果使用 || 来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如'',0,NaN,false)时。见下面的例子。
const foo = "" ?? 'default string';
const foo2 = "" || 'default string';
console.log(foo); // ""
console.log(foo2); // "default string"
const baz = 0 ?? 42;
const baz2 = 0 || 42;
console.log(baz); // 0
console.log(baz2); // 42
注意点
将 ?? 直接与 AND(&&)和 OR(||)操作符组合使用是不可取的。
null || undefined ?? "foo"; // 抛出 SyntaxError
true || undefined ?? "foo"; // 抛出 SyntaxError
可选链与空值合并操作符一起使用
let customer = {
name: "jimmy",
details: { age: 18 }
};
let customerCity = customer?.city ?? "成都";
console.log(customerCity); // "成都"
ES12新特性
1.逻辑运算符和赋值表达式(&&=,||=,??=)
1.&&=
逻辑与赋值 x &&= y等效于:
x && (x = y);
复制代码
上面的意思是,当x为真时,x=y。具体请看下面的示例:
let a = 1;
let b = 0;
a &&= 2;
console.log(a); // 2
b &&= 2;
console.log(b); // 0
复制代码
2.||=
逻辑或赋值(x ||= y)运算仅在 x 为false时赋值。
x ||= y 等同于:x || (x = y);
const a = { duration: 50, title: '' };
a.duration ||= 10;
console.log(a.duration); // 50
a.title ||= 'title is empty.';
console.log(a.title); // "title is empty"
复制代码
3.??=
逻辑空赋值运算符 (x ??= y) 仅在 x 是 nullish[3] (null 或 undefined) 时对其赋值。
x ??= y 等价于:x ?? (x = y);
示例一
const a = { duration: 50 };
a.duration ??= 10;
console.log(a.duration); // 50
a.speed ??= 25;
console.log(a.speed); // 25
复制代码
示例二
function config(options) {
options.duration ??= 100;
options.speed ??= 25;
return options;
}
config({ duration: 125 }); // { duration: 125, speed: 25 }
config({}); // { duration: 100, speed: 25 }
复制代码
2.String.prototype.replaceAll()
介绍
replaceAll() 方法返回一个新字符串,新字符串中所有满足 pattern 的部分都会被replacement 替换。pattern可以是一个字符串或一个RegExp,replacement可以是一个字符串或一个在每次匹配被调用的函数。
原始字符串保持不变。
示例
'aabbcc'.replaceAll('b', '.'); // 'aa..cc'
使用正则表达式搜索值时,它必须是全局的。
'aabbcc'.replaceAll(/b/, '.');
TypeError: replaceAll must be called with a global RegExp
这将可以正常运行:
'aabbcc'.replaceAll(/b/g, '.');
"aa..cc"
3.数字分隔符
欧美语言中,较长的数值允许每三位添加一个分隔符(通常是一个逗号),增加数值的可读性。比如,1000可以写作1,000。
ES2021中允许 JavaScript 的数值使用下划线(_)作为分隔符。
let budget = 1_000_000_000_000;
budget === 10 ** 12 // true
这个数值分隔符没有指定间隔的位数,也就是说,可以每三位添加一个分隔符,也可以每一位、每两位、每四位添加一个。
123_00 === 12_300 // true
12345_00 === 123_4500 // true
12345_00 === 1_234_500 // true
小数和科学计数法也可以使用数值分隔符。
// 小数
0.000_001
// 科学计数法
1e10_000
数值分隔符有几个使用注意点。
- 不能放在数值的最前面(leading)或最后面(trailing)。
- 不能两个或两个以上的分隔符连在一起。
- 小数点的前后不能有分隔符。
- 科学计数法里面,表示指数的
e或E前后不能有分隔符。
下面的写法都会报错。
// 全部报错
3_.141
3._141
1_e12
1e_12
123__456
_1464301
1464301_
4.Promise.any
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。
const promise1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise1");
// reject("error promise1 ");
}, 3000);
});
};
const promise2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise2");
// reject("error promise2 ");
}, 1000);
});
};
const promise3 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise3");
// reject("error promise3 ");
}, 2000);
});
};
Promise.any([promise1(), promise2(), promise3()])
.then((first) => {
// 只要有一个请求成功 就会返回第一个请求成功的
console.log(first); // 会返回promise2
})
.catch((error) => {
// 所有三个全部请求失败 才会来到这里
console.log("error", error);
});
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
Promise.any()跟Promise.race()方法很像,只有一点不同,就是Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。