ES2017标准引入了诸多更实用的语法,如引入了async/await函数、幂运算符、Null传导运算符?.、装饰器等。
async/await 异步编程终级解决方案
async函数就是Generator函数的语法糖
async函数返回一个promise对象,并且把内部的值进行promise的封装,当async函数执行时遇到await就会先返回,等到异步操作完成,再接着执行函数体后面的语句,如果函数中return一个直接量,async会把这个直接量通过Promise.resolve()封装成Promise对象,在没有await的情况下执行async函数,它会立即执行,返回一个promise对象,不会阻塞后面的语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 // async/await 与 generator函数对比
var fs = require('fs');
var readFile = function (fileName){
return new Promise(function (resolve, reject){
fs.readFile(fileName, function(error, data){
if (error) reject(error)
resolve(data)
})
})
}
// Generator * yield 解决异步
var gen = function* (){
var f1 = yield readFile('/etc/fstab')
var f2 = yield readFile('/etc/shells')
console.log(f1.toString())
console.log(f2.toString())
}
// async await 解决异步
var asyncReadFile = async function (){
var f1 = await readFile('/etc/fstab')
var f2 = await readFile('/etc/shells')
console.log(f1.toString())
console.log(f2.toString())
}
/* async函数就是将Generator函数的星号*换成async,将yield换成await
async 的改进:1. 比起星号和yield语义更清楚了,async表示函数里有异步操作,await表示
后面的代码需要等待结果 2. async函数返回值是promise对象,使用then指定下一步操作 */
await
关键字只能放到async
函数里面,不可以脱离async单独使用,等待后面的promise对象执行完毕,然后拿到promise resolve 的值并进行返回,返回值拿到之后,它继续向下执行await
后面一定是Promise对象,如果不是会自动包装成Promise对象await
如果它等到的不是一个Promise
对象,那await
表达式的运算结果就是它等到的东西。await
如果它等到的是一个Promise
对象,await
会阻塞后面的代码,等着Promise
对象resolve
,然后得到resolve
的值,作为await
表达式的运算结果1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30// async 返回 promise 对象
async function test(){
return 4
}
console.log(test()) // Promise {<resolved>: 4}
test().then(res => {console.log(res)}) // 4
async function test1(){
return new Promise((resolve, reject) =>{
resolve(4)
})
}
console.log(test1()) // Promise {<pending>}
test1().then(res => {console.log(res)}) // 4
// async 与 await 的使用
function getGoodsId() {
return new Promise(resolve => {
setTimeout(() => resolve("商品id"), 1000)
})
}
// 也可以使用如下写法
// async function getGoodsId() {
// await new Promise(resolve => {
// setTimeout(() => resolve("商品id"), 1000)
// })
// }
async function test() {
console.log(await getGoodsId())
}
test() // 商品idawait 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try…catch 代码块中。
1
2
3
4
5
6
7
8
9
10
11
12
13async function fun() {
try {
await asyncFun()
} catch (err) {
console.log(err)
}
}
// 另一种写法
async function myFunction() {
await asyncFun().catch(function (err){
console.log(err)
})
}async/await
遇上map
的遍历操作时,当async
函数被执行时,将立即返回pending
状态的Promise
,因此,在map
循环时,不会等待await
操作完成,而是直接进入下一次循环。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18let arr = [1, 2, 3]
let res = arr.map(value => {
return value * 2
})
console.log(res) // [2, 4, 6]
let arr1 = [1, 2, 3]
let res1 = arr1.map(async value => {
return value * 2
})
console.log(res1) // [Promise, Promise, Promise]
// 使用 Promise.all() 将async返回的promise对象数组依次执行
let arr1 = [1, 2, 3]
let res1 = await Promise.all(arr1.map(async value => {
return value * 2
}))
console.log(res1) // [2, 4, 6]
BigInt
1 | console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991 |
幂运算 **
1 | // n**m 等同于 Math.pow(n, m) n的m次方 |
Null 传导运算符 ?.
如果读取对象内部的某个属性,往往需要判断该对象是否存在,该属性的上层属性是否存在
1
2
3
4const obj = { teacher: {info: {age: 22}} }
const age = (obj && obj.teacher && obj.teacher.info && obj.teacher.info.age) || 18
// 这样的层层判断非常麻烦,使用 ?. 简化 只要其中一个返回null或undefined,就不再往下运算
const age = obj?.teacher?.info?.age || 18
catch语句的参数
允许try...catch结构中的catch语句调用时不带参数
1
2
3try {} catch (error) {} // 传统写法,catch语句必须有参数,用来接收try代码块抛出的错误
// 新的写法允许省略catch后面的参数
try {} catch {}
装饰器
装饰器可以修饰类 类的属性 类的原型上的方法 修饰的时候就是把这个类的属性传递给修饰的函数