ES6 新特性梳理系列丨异步操作

ES6 新特性梳理系列文章将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!


JavaScript 与 ECMAScript

JavaScript 诞生于1995年,设计者是就职于 Netscape 公司的工程师 Brendan Eich。它是一门仅用10天就完成设计的编程语言,但至今为止已对业界保持26年的影响,且势头愈发强劲

1996年 Netscape 将 JavaScript 提交给ECMA,希望它可以成为“标准化一个通用的、跨平台的、中立于厂商的脚本语言的语法和语义标准”,1997年 ECMA 确定将 JavaScript 作为浏览器脚本语言的标准,并为之重命名为 ECMAScript,所以通常来讲我们将 ECMAScript 视为 JavaScript 的标准,而 JavaScript 则是 ECMAScript 的实现及扩展

1997年-1999年连续发布了ES1-ES3发布,2000年开始酝酿新版本的升级内容,中间因标准委员会意见未能达成一致,只做了部分功能的小范围升级及支持,于2009年12月发布了过渡版 ECMAScript 5.0,2011年6月发布 ECMAScript 5.1 并成为 ISO 国际标准

2013年3月 ECMAScript 6 草案冻结,2013年12月 ECMAScript 草案发布,2015年6月 ECMAScript 6 正式通过,成为新的国际标准。ES6 泛指自2015年升级为 ECMAScript 6.0 后的所有子版本,如:ES2015-ES2020,等同于ES6.0-ES6.5,这是 JavaScript 走向企业级编程语言的强势升级

不断升级的标准与实现,对于开发效率及产品质量起到强有力的支撑,接下来我们开始梳理ES6的新特性吧!


什么是异步操作

打个生活中的例子,异步就是你去买饭,告诉厨师开始做饭,然后做饭的时候你去旁边超市买饮料,等饭做好了,厨师给你打了个电话,然后你回到饭店开始吃饭。在告诉厨师开始做饭和吃饭的这个过程中,你去买了瓶饮料。

将一个任务分成了两节,开始你做了一节,然后去做别的事情了,等做好了准备,再回头执行第二节。

那么相比较同步就很明显了,就是你告诉厨师开始做饭以后,你就在饭店等着,等着吃饭,吃完了饭,你再去买的饮料。连续的执行就叫做同步,由于是连续执行,不能插入其他任务,所以你从做饭到吃饭的这段时间,你什么也做不了,只能等着。


回调函数

JavaScript 对异步编程的实现,就是回调函数。

回调函数,就是把任务分成两端,把第二段单独写在一个函数里,当任务执行成功后,就直接调用这个函数。英文名叫“callback”,中文意思就是“重新调用”。

比如,有一个需求,我们要在一个异步操作完成之后,进行一些其他操作,应该怎么办呢?(这里用定时器作为异步操作来举例)

setTimeout(() => {
  var data = 'hello'
},1000)

在上面代码里,我们想要在定时器结束以后,输出这个 data 的值,应该怎么做呢?

// 错误做法
setTimeout(() => {
  var data = 'hello'
},1000)
console.log(data)
// Uncaught ReferenceError: data is not defined

程序会优先执行同步操作,也就是执行第5行,但是当执行这行的时候,data还没有定义呢,所以程序报错。

// 正确做法
setTimeout(() => {
   var data = 'hello'
   console.log(data)
},1000)
// hello

上面代码将 console 语句移到了定时器内部,在1秒后会输出 data 的值。

但是,如果我们要进行的操作是不确定的呢?比如我们想在拿到这个 data 的时候,拼接上 ‘world’ 字符串怎么办呢?这时候就需要回调函数了。

// 回调函数写法
function fn(callback){
  setTimeout(() => {
     var data = 'hello'
     callback(data)
  },1000)
}


// 调用fn函数
fn(function(data){
  console.log(data + 'world')
})
// helloworld

上面代码,调用 fn() 的时候,参数是一个函数,这个函数里面就是我们对异步操作结果 data 进行的操作。


Promise

本系列前面已经介绍过 Promise,这里我们直接用 Promise 来对上面的回调函数进行改造。

// promise 方式


var pro = new Promise(function(resolve,reject){
  setTimeout(()=>{
    var data = 'hello'
    resolve(data)
  },1000)
})


pro.then((data)=>{
  console.log(data + 'world')
})
// helloworld

有关Promise的详细介绍,请移步ES6 新特性梳理系列丨Promise 对象


Generator


本系列前面已经介绍过 Generator,这里我们也是直接用 Generator 来对上面的回调函数进行改造,并且加上额外的需求,模拟获取接口请求,获取用户数据、订单数据、商品数据,但是是有先后顺序的,要先获取用户数据,才能获取订单数据,先获取订单数据,才可以获取商品数据。

// Generator 形式


// 获取用户数据
function getUsers(){
  setTimeout(()=>{
    var data = '用户数据'
    // 调用next方法,并且将数据传入
    iterator.next(data) // data 将会作为第一个yield语句的返回结果
  },1000)
}


// 获取订单数据
function getOrders(){
  setTimeout(()=>{
    var data = '订单数据'
    // 调用next方法,并且将数据传入
    iterator.next(data) // data 将会作为第二个yield语句的返回结果
  },1000)
}


// 获取商品数据
function getGoods(){
  setTimeout(()=>{
    var data = '商品数据'
    // 调用next方法,并且将数据传入
    iterator.next(data) // data 将会作为第三个yield语句的返回结果
  },1000)
}


// 生成器函数
function * gen(){
  let users = yield getUsers()
  console.log(users) // 用户数据
  let orders = yield getOrders()
  console.log(orders) // 订单数据
  let goods = yield getGoods()
  console.log(goods) // 商品数据
}
// 调用生成器函数
let iterator = gen()
iterator.next() 
// 运行第一个 yield语句(第27行),并且将结果返回,
// 本例中,此处返回结果是undefined

有关 Generator 的详细介绍,请移步ES6 新特性梳理系列丨Generator 函数


async

async 和 await 是ES8 的新特性,可以让异步代码像同步代码一样。

先来说 async 函数,async 函数的返回结果是一个 promise 对象,promise对象的结果由 async 函数执行的返回值决定。

async function fn(){
  return 'hello'
}
console.log(fn())
// Promise {<fulfilled>: "hello"}
//    __proto__: Promise  
//    [[PromiseState]]: "fulfilled"   
//    [[PromiseResult]]: "hello"  

上面返回的 Promise 结果是 fulfilled,成功的值是 hello。如果我们不返回值呢?

async function fn(){
  return
}
console.log(fn())
// Promise {<rejected>: undefined }
//    __proto__: Promise  
//    [[PromiseState]]: "fulfilled"   
//    [[PromiseResult]]: undefined 

上面返回的 Promise 结果是 fulfilled,成功的值是 undefined。如果我们抛出一个错误呢?

async function fn(){
  throw new Error('出错了')
}
console.log(fn())
// Promise {<fulfilled>: Error: 出错了 }
//    __proto__: Promise  
//    [[PromiseState]]: "rejected"   
//    [[PromiseResult]]: Error: 出错了

上面返回的 Promise 结果是 rejected,失败的值是失败的 Error 对象。

现在让我们在 async 函数中写入一个 promise 对象。

async function fn(){
  return new Promise((resolve,reject)=>{
    resolve('成功')
  })
}
console.log(fn())
// Promise {<fulfilled>: "成功"}
//    __proto__: Promise  
//    [[PromiseState]]: "fulfilled"   
//    [[PromiseResult]]: "成功"  


async function foo(){
  return new Promise((resolve,reject)=>{
    reject('失败')
  })
}
console.log(foo())
// Promise {<rejected>: "失败"}
//    __proto__: Promise  
//    [[PromiseState]]: "rejected"   
//    [[PromiseResult]]: "失败"

可见,内部 promise 返回的值和状态,决定了 async 返回的 Promise 对象的值和状态。


await

现在我们再来看 await。

await 函数必须写在 async 函数内部,但是 async 内部不一定要有 await 函数;await 函数右侧是一个 Promise 对象,await 返回的是右侧 Promise 成功的值,如果 await 右边的 Promise 失败了,就会抛出一个异常,我们需要使用 try...catch 捕获处理。

var pro = new Promise((resolve,reject=>{
  resolve('成功')
}))


async function fn(){
  let data = await pro
  console.log(data)
  // 成功
}




var promise= new Promise((resolve,reject=>{
  reject('失败')
}))


async function fn(){
  try{
    // promise 成功走这里
    let data = await promise
    console.log(data)
  }catch(e){
    // promise 失败走这里
    console.log(e)
    // 失败
  }
}


最后,我们将 await 和 async 结合的方式,来对上一个获取用户数据、订单数据、商品数据的例子进行改造。

// 获取用户数据
function getUsers(){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      var data = '用户数据'
      resolve(data)
    },1000)
  })
}


// 获取订单数据
function getOrders(){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      var data = '订单数据'
      resolve(data)
    },1000)
  })
}


// 获取商品数据
function getGoods(){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      var data = '商品数据'
      resolve(data)
    },1000)
  })
}


// 定义async函数
async function fn(){
 let users = await getUsers()
 let orders = await getOrders()
 let goods = await getGoods()
 console.log(users)
 console.log(orders)
 console.log(goods)
}
// 调用fn()
fn()
// '用户数据'
// '订单数据'
// '商品数据'

ES6 新特性梳理系列文章将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!

叶阳辉

HFun 前端攻城狮

往期精彩:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值