ECMAScript 8 新特性
1. async 和 await
async 和 await 两种语法结合可以让异步代码像同步代码一样。(即:看起来是同步的,实质上是异步的。)
先从字面意思理解,async 意为异步,可以用于声明一个函数前,该函数是异步的。await 意为等待,即等待一个异步方法完成。
1.1 async
async 声明(function)的函数成为 async 函数,语法:
async function funcName() {
//statements
}
async 内部可以使用 await,也可以不使用。
async 函数的返回值是一个 Promise 对象,因此执行这个函数时,可以使用 then 和 catch 方法。
根据 函数体内部 的返回值, async 函数返回值具体情况如下:
-
函数体内不返回任何值,则
async函数返回值为一个成功(fulfilled)的Promise对象,状态值为undefined。let a = async function() {} let res = a() console.log(res) // Promise{<fullfilled>: undefined} -
返回结果不是一个
Promise,则async函数返回值为一个成功(fulfilled)的Promise对象,状态值为这个内部返回值。let a = async function () { return 'hello' } let res = a() console.log(res) // Promise{<fullfilled>: 'hello'} -
内部抛出错误,则
async函数返回值为一个失败的Promise对象。let a = async function foo() { throw new Error('出错了') } a().catch(reason => { console.log(reason) }) -
若函数内部返回值是一个
Promise对象,则async函数返回值的状态取决于这个Promise对象。let a = async function () { return new Promise((resolve, reject) => { resolve("成功") }) } a().then(value => { console.log(value) })
1.2 await
await 相当于一个运算符,右边接一个值。一般为一个 Promise 对象,也可以是一个非 Promise 类型。当右接一个非 Promise 类型,await 表达式返回的值就是这个值;当右接一个 Promise 对象,则 await 表达式会阻塞后面的代码,等待当前 Promise 对象 resolve 的值。
综合 async 和 await 而言。await 必须结合 async 使用,而 async 则不一定需要 await。 async 会将其后的函数的返回值封装成一个 Promise 对象,而 await 会等待这个 Promise 完成,然后返回 resolve 的结果。当这个 Promise 失败或者抛出异常时,需要时使用 try-catch 捕获处理。
Promise 使用链式调用解决了传统方式回调地狱的问题,而 async-await 又进一步优化了代码的可读性。
const p = new Promise((resolve, reject)=>{
resolve('成功')
})
async function main() {
let res = await p
console.log(res)
}
main()
// '成功'
const p = new Promise((resolve, reject)=>{
reject('失败')
})
async function main() {
try {
let res = await p
console.log(res)
} catch(e) {
console.log(e)
}
}
main()
// '失败'
1.3 综合应用-读取文件
需求:先读取用户数据 user,然后读取订单数据 order,最后读取商品数据 goods。
对于这种异步操作很容易想到使用 Promise,代码如下:
const fs = require('fs')
let p = new Promise((resolve, reject) => {
fs.readFile('./files/user.md', (err, data) => {
if (err) reject(err)
resolve(data)
})
})
p.then(value => {
return new Promise((resolve, rejecet) => {
fs.readFile('./files/order.md', (err, data) => {
if (err) rejecet(err)
resolve([value, data])
})
})
}, reason => {
console.log(reason)
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile('./files/goods.md', (err, data) => {
if (err) reject(err)
value.push(data)
resolve(value)
})
})
}, reason => {
console.log(reason)
}).then(value => {
console.log(value.join('\n'))
}, reason => {
console.log(reason)
})
但是,使用 Promise 链式调用虽然避免了回调地狱,但这种链式调用过多难免引起代码复杂,看起来不直观。可以使用 async 和 await 方法优化,代码如下:
const fs = require('fs')
function readUser() {
return new Promise((resolve, reject) => {
fs.readFile('./files/user.md', (err, data) => {
if (err) reject(err)
resolve(data)
})
})
}
function readOrder() {
return new Promise((resolve, reject) => {
fs.readFile('./files/order.md', (err, data) => {
if (err) reject(err)
resolve(data)
})
})
}
function readGoods() {
return new Promise((resolve, reject) => {
fs.readFile('./files/goods.md', (err, data) => {
if (err) reject(err)
resolve(data)
})
})
}
async function read() {
let user = await readUser()
let order = await readOrder()
let goods = await readGoods()
console.log([user, order, goods].join('\n'))
}
read()
这样,代码看起来很直观,就好像是同步代码一样,实际上是异步操作。
1.4 综合应用-封装ajax
function sendAjax(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
}
reject(xhr.status)
}
}
})
}
async function main() {
let res = await sendAjax('http://poetry.apiopen.top/sentences')
let poem = res.result.name + '——' + res.result.from
document.body.innerText = poem
}
main()
这里封装的ajax还不能体现 async-await 的作用所在,因为没有出现多个 ajax 请求。在又多个 ajax 请求并且后续的请求依赖于前一个请求的结果的时候,async-await 的优点就体现出来了。
2. Object.values 和 Object.entries
-
Object.values()方法返回一个给定对象的所有可枚举属性值的数组,类似于Object.keys(),只是前者返回属性值,后者返回键值组合的数组。let obj = { a: 1, b: {1:2}, c: [1,2,3] } console.log(Object.values(obj)) // [1, {1: 2}, [1,2,3]] console.log(Object.keys(obj)) // ['a', 'b', 'c'] -
Object.entries()方法返回一个给定对象自身可遍历属性[key,value]的数组(数组元素也是一个个的数组的数组)const obj = {a: 1, b: 2, c: 3}; console.log(Object.entries(obj)) // [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]返回的是一个数组,这样就可以使用
for...of遍历了。const obj = { a: 1, b: 2, c: 3 }; for (let [k, v] of Object.entries(obj)) { console.log(k, v) }
本文介绍了ECMAScript8中的新特性,重点讲解了async和await的使用,如何简化异步代码,以及它们与Promise的配合。通过实例展示了如何读取文件和封装ajax请求,说明了async/await如何提高代码可读性和避免回调地狱。同时,提到了Object.values和Object.entries方法,用于获取对象的值和键值对数组,增强代码的可操作性。
300

被折叠的 条评论
为什么被折叠?



