前端promise与async、await(异步编程)

promise

Promise是ES6异步编程的一种解决方案(目前最先进的解决方案是async和await的搭配(ES8),但是它们是基于promise的),从语法上讲,Promise是一个对象或者说是构造函数,用来封装异步操作并可以获取其成功或失败的结果。

为什么使用promise

1.可以避免多层异步调用嵌套问题(回调地狱)
2.Promise 对象提供了简洁的API,使得控制异步操作更加容易(js执行机制导致的异步问题

promise的三种状态

1.pending: 等待中,或者进行中,表示还没有得到结果
2.resolved(Fulfilled): 已经完成,表示得到了我们想要的结果,可以继续往下执行
3.rejected: 也表示得到结果,但是由于结果并非我们所愿,因此拒绝执行

这三种状态不受外界影响,而且状态只能从pending改变为resolved或者rejected,并且不可逆


promise的用法

promise的实例方法

①then()得到异步任务的正确结果

②catch()获取异常信息

注意:then方法可以接受两个函数,第一个函数为promise状态为成功的回调函数,第二个函数为promise状态为失败的回调函数可以不写,一般用catch方法捕获promise状态为失败的异常信息)


function fn(flag) {
    return new Promise(function(resolve, reject) {
        if (flag === true) {
            resolve('promise状态为成功!')
        };
        if (flag === false) {
            reject('promise状态失败!')
        };
    }).then(res=>{
      console.log(res)
    }).catch(err=>{
      console.log(err)
    })
}
fn(true)
fn(false)
	

在前端中,ajax和axios都会用到异步编程,axios更是基于promise的,所以一定要掌握promise以及用async和await搭配promise的使用

异步函数async和await的用法

async

async的用法,语法很简单,在函数前面加上async关键字,表示函数是异步的。

只有一个作用,他的调用会返回一个promise对象。

async function timeout() {
  console.log("执行")
  return 'hello world!'
}
console.log(timeout())
console.log('11')

如果async函数中有返回值,当调用该函数时,内部会调用Promise.resolve()方法把它转化成一个promise对象作为返回

//所以下面这个示例完全可以正确运行
    function getSomething () {
      return 'something'
    }
    async function testAsync () {
      return  'hello async'
    }
    function test () {
      const v1 =getSomething()
      const v2 =  testAsync()
      console.log(v1, v2)
    }
    test()

这两种方法是等效的

// 方法1
function f() {
  return Promise.resolve('TEST');
}// asyncF is equivalent to f!

// 方法2
async function asyncF() {
  return 'TEST';
}

那么要想获取到async 函数的执行结果,就要调用promise的then 或 catch 来给它注册回调函数

async 关键字差不多了,最重要的就是async函数的执行会返回promise对象,并且把内部的值进行promise的封装

await

await关键字只能放到async函数里面,await是等待的意思,await不仅仅用于等Promise对象,还可以等任意表达式,所以await后面实际是可以接普通函数调用或者直接量的

不过我们更多的是放一个返回promise 对象的表达式。他等待的是promise对象执行完毕,并返回结果

//所以下面这个示例完全可以正确运行
    function getSomething () {
      return 'something'
    }
    async function testAsync () {
      return  'hello async'
    }
    async function test () {
      const v1 = await getSomething()
      const v2 = await testAsync()
      console.log(v1, v2)
    }
    test()

如果它等到的不是一个Promise对象,那么await表达式的运算结果就是它等到的东西。

如果它等到的是一个Promise对象,await就忙起来了,它会阻塞函数后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运算结果。

await 优势在于处理 then 链,使代码看起来像同步代码一样
// 2s 之后返回双倍的值
function doubleAfter2seconds (num) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(num * 2)
        }, 2000)
      })
    }

async function testResult() {
    let first = await doubleAfter2seconds(30);
    let second = await doubleAfter2seconds(50);
    let third = await doubleAfter2seconds(30);
    console.log(first + second + third);
}
testResult()

await 表示等待,代码就暂停到这里,不再向下执行了,它等待后面的promise对象执行完毕,然后拿到promise resolve 的值并进行返回,返回值拿到之后,它继续向下执行

具体到 我们的代码, 遇到await 之后,代码就暂停执行了, 等待doubleAfter2seconds(30) 执行完毕,doubleAfter2seconds(30) 返回的promise 开始执行,2秒 之后,promise resolve 了, 并返回了值为60, 这时await 才拿到返回值60, 然后赋值, 暂停结束,代码继续执行,最后以此类推执行 console.log语句。

function doubleAfter2seconds (num) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(num * 2)
    }, 2000)
  })
}

async function testResult() {
  let first = await doubleAfter2seconds(30);
  console.log(first );
}
testResult()

console.log('我先执行!!!')

当js引擎在等待promise.resolve的时候,他并没有真正的暂停工作,它可以处理其他的一些事情,如果我们在testResult函数后面继续执行其他代码,比如console.log一下,会发现console.log代码先执行。

async function fn1 (){
  console.log(1)
  await fn2() // fn2进入微任务队列等待执行
  console.log(2) // 阻塞
}
async function fn2 (){
  console.log('fn2')
}
fn1()
console.log(3)

// 输出结果:1,fn2,3,2

await 会阻塞它下面的代码(即加入微任务队列),先执行 async 外面的同步代码,同步代码执行完,再回到 async 函数中,再执行之前阻塞的代码。

await示例

async function async1() {
	console.log('async1 start');
	await async2();
	console.log('async1 end');
}

等价于

async function async1() {
	console.log('async1 start');
	Promise.resolve(async2()).then(() => {
                console.log('async1 end');
        })
}

总结

async 函数

1)函数的返回值为Promise对象

2)Promise对象的结果由async函数执行的返回值决定

await 表达式

1)正常情况下,await右侧的表达式一般为 promise对象 , 但也可以是其它的值

2)如果表达式是promise对象,await就忙起来了,它会阻塞函数后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运算结果。

3)如果表达式是其它值, 直接将此值作为await的返回值

async和await基于promise的。使用async的函数将会始终返回一个 promise 对象。这一点很重要,要记住,可能是你遇到容易犯错的地方。

在使用await的时候我们只是暂停了函数,而非整段代码。这里经常会是容易犯错的地方。

async和await是非阻塞的

仍然可以使用 Promise,例如Promise.all(p1, p2, p3).,接受一个数组作为参数,p1、p2、p3 都是 Promise 实例,如果不是,就会先调用 Promise .resolve方法,将参数转为 Promise 实例,再进一步处理。只要 p1、p2、p3 之中有一个被 rejected,整个状态就变成 rejected。

注意

1)await必须写在async函数中, 但async函数中可以没有await

2)如果await的promise失败了, 就会抛出异常, 需要通过try…catch来捕获处理

// promise
getInfo()
  .then(res => {
    //do somethings
  })
  .catch(err => {
    //do somethings
  })

// async/await
try {
  const res = await getInfo()
  //do somethings
} catch (error) {
  //do somethings
}

本文结合了csdn上的相关文章汇总教程,部分图片直接搬运上来了,希望对读者有帮助!

(仅做技术交流分享)

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值