ECMAScript 8 新特性

本文介绍了ECMAScript8中的新特性,重点讲解了async和await的使用,如何简化异步代码,以及它们与Promise的配合。通过实例展示了如何读取文件和封装ajax请求,说明了async/await如何提高代码可读性和避免回调地狱。同时,提到了Object.values和Object.entries方法,用于获取对象的值和键值对数组,增强代码的可操作性。

ECMAScript 8 新特性

1. async 和 await

asyncawait 两种语法结合可以让异步代码像同步代码一样。(即:看起来是同步的,实质上是异步的。)

先从字面意思理解,async 意为异步,可以用于声明一个函数前,该函数是异步的。await 意为等待,即等待一个异步方法完成。

1.1 async

async 声明(function)的函数成为 async 函数,语法:

async function funcName() {
    //statements 
}

async 内部可以使用 await,也可以不使用。
async 函数的返回值是一个 Promise 对象,因此执行这个函数时,可以使用 thencatch 方法。
根据 函数体内部 的返回值, 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 的值。

综合 asyncawait 而言。await 必须结合 async 使用,而 async 则不一定需要 awaitasync 会将其后的函数的返回值封装成一个 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 链式调用虽然避免了回调地狱,但这种链式调用过多难免引起代码复杂,看起来不直观。可以使用 asyncawait 方法优化,代码如下:

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)
    }
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值