javaScript---读懂promise、async/await

目录

1、Promise

2、async/await

3、为什么async/await更好?


1、Promise

Promise 是一个 Es 6 提供的类,目的是更加优雅地书写复杂的异步任务。可以解决嵌套式的回调地域问题,Promise 将嵌套格式的代码变成了顺序格式的代码。

//回调地域
setTimeout(function () {
  console.log("红灯");
  setTimeout(function () {
    console.log("绿灯");
    setTimeout(function () {
      console.log("黄灯");
    }, 1000);
  }, 2000);
}, 3000);

//promise.then链式调用解决回调地域问题, Promise 将嵌套格式的代码变成了顺序格式的代码。
new Promise(function (resolve, reject) {
  setTimeout(function () {
    console.log("red");
    resolve();
  }, 3000);
})
  .then(function () {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        console.log("green");
        resolve();
      }, 2000);
    });
  })
  .then(function () {
    setTimeout(function () {
      console.log("yellow");
    }, 1000);
  });

三种状态:pending 、fulfilled、rejected

Promise 对象代表一个异步操作,有三种状态 :pending 等待、fulfilled完成/成功、rejected拒绝/失败只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

promiise状态变化不可逆

等待->成功:Promise对象的状态可以从pending变为fulfilled,并携带了成功的结果value。通过resolve触发,fulfilled状态会触发后续的then回调

等待->失败:也可以从pending变为rejected。携带失败的理由reason。通过reject触发,rejected状态会触发后续的catch回调

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供。

resolve函数的作用是,将Promise对象的状态从pending变为Resolved(或fulfilled),在异步操作成功时调用,并将异步操作的结果value作为参数传递出去。

reject函数的作用是,将Promise对象的状态从Pending变为Rejected,在异步操作失败时调用,并将异步操作报出的错误作为参数传递出去

使用 then 方法处理 Promise 成功状态的回调函数

使用 catch 方法处理 Promise 失败状态的回调函数

let promise = new Promise((resolve, reject) => {
  // 接收一个callback。参数是成功函数与失败函数
  setTimeout(() => {
    let num = parseInt(Math.random() * 100);
    console.log("num=", num);
    // 如果数字大于50就调用成功的函数,并且将状态变成Resolved
    if (num > 50) {
      resolve("成功");
    } else {
      // 否则就调用失败的函数,将状态变成Rejected
      reject("失败");
    }
  }, 1000);
});
//使用 then 方法处理 Promise 成功状态的回调函数,使用 catch 方法处理 Promise 失败状态的回调函数
promise
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {
    console.log(err);
  });

then 方法可以接收两个回调函数作为参数,第一个回调函数是Promise对象的状态改变为 resoved 是调用,第二个回调函数是 Promise 对象的状态变为 rejected 时调用。其中第二个参数可以省略。

catch 方法,该方法相当于 最近的then 方法的第二个参数,指向 reject 的回调函数,另一个作用是,在执行resolve回调函数时,如果出错,抛出异常,进入catch 方法中。

finally 方法是在 Promise 执行的最后一定会执行的序列

注意:

then、catch返回的promise是新的promise,不是原来的promise。

promise对象的错误会“冒泡”,直到被捕获为止,错误会被下一个catch语句捕获。

catch 只捕获最近的 then 的回调函数,前面的then的执行不成功的结果,有后面 then 的 reject 回调函数执行,如果没有后续 then 回调函数执行,则会被 catch 捕获执行;

then和catch对状态的影响

  • then正常返回fulfilled,里面有报错返回rejected
  • catch正常返回fulfilled,里面有报错返回rejected
const p1 = Promise.resolve().then(()=>{
  return 100
})
console.log('p1', p1) // fulfilled会触发后续then回调
p1.then(()=>{
  console.log(123)
}) // 打印123

const p2 = Promise.resolve().then(()=>{
  throw new Error('then error')
})
// p2是rejected会触发后续catch回调
p2.then(()=>{
  console.log(456)
}).catch(err=>{
  console.log(789)
})
// 打印789
const p1 = Promise.reject("my error").catch(() => {
  console.log("catch error");
});
p1.then(() => {
  console.log(1); //打印1
});

const p2 = Promise.reject("my error").catch(() => {
  throw new Error("catch error");
});

p2.then(() => {
  console.log(2);
}).catch(() => {
  console.log(3); //打印3
});
// 第一题
Promise.resolve()
.then(()=>console.log(1))// 状态返回fulfilled
.catch(()=>console.log(2)) // catch中没有报错,状态返回fulfilled,后面的then会执行
.then(()=>console.log(3)) // 1,3
// 整个执行完没有报错,状态返回fulfilled

// 第二题
Promise.resolve()
.then(()=>{ // then中有报错 状态返回rejected,后面的catch会执行
  console.log(1)
  throw new Error('error')
})
.catch(()=>console.log(2)) // catch中没有报错,状态返回fulfilled,后面的then会执行
.then(()=>console.log(3)) // 1,2,3
// 整个执行完没有报错,状态返回fulfilled

// 第三题
Promise.resolve()
.then(()=>{//then中有报错 状态返回rejected,后面的catch会执行
  console.log(1)
  throw new Error('error')
})
.catch(()=>console.log(2)) // catch中没有报错,状态返回fulfilled,后面的catch不会执行
.catch(()=>console.log(3)) // 1,2
// 整个执行完没有报错,状态返回fulfilled

promise.all

promise.all可以将多个promise实例包装成一个新的promise实例。同时,成功和失败的返回值是不同的,
成功的时候返回一个数组,失败时则返回最先被reject失败的状态的值。
所有的请求都完成时,才返回一个数组
只要有一个失败了,就先返回这个失败的请求

        let p1 = new Promise((resolve,reject) => {
            resolve('成功了')
        })

        let p2 = new Promise((resolve,reject) => {
            resolve('success')
        })

        let p3 = new Promise((resolve,reject) => {
            reject('失败了')
        }) 

        Promise.all([p1, p2]).then(res => {
            console.log(res)  //[ '成功了', 'success' ]
        }).catch(err => {
            console.log(err)
        })

        Promise.all([p1, p2, p3]).then(res => {
            console.log(res)  
        }).catch(err => {
            console.log(err) // 失败了
        })

promise.race

顾名思义,promise.race就是赛跑的意思,就是说promise.race([p1, p2, p3])里哪个结果捕获的快,就返回哪个结果
不管成功还是失败

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("成功了");
  }, 1000);
});

let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("失败了");
  }, 500);
});

Promise.race([p1, p2])
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {
    console.log(err);
  });

 Promise 优点

 Promise 对象可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数;

Promise 对象提供统一的接口,使得控制异步操作更加容易。

 Promise 缺点

无法取消 Promise,一旦新建它就会立即执行,无法中途取消;

如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部;

当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

2、async/await

async/await是es7出的一种解决异步的一种方案, 背后原理就是promise。

  • async 封装 Promise
  • await 处理 Promise 成功
  • try...catch 处理 Promise 失败

async:当一个函数前面加上async,那么他就成了一个异步函数。async函数会返回一个promise对象。可以使用 then 方法添加回调函数。

async function helloAsync(){
    return "helloAsync";
  }
  
console.log(helloAsync())  // Promise {<resolved>: "helloAsync"}
 
helloAsync().then(v=>{
   console.log(v);         // helloAsync
})

await:await 操作符用于等待一个 Promise 对象, 它只能在异步函数 async function 内部使用。它相当于promise的then,await是同步写法,但本质还是异步调用。

正常情况下,await 命令后面是一个 Promise 对象,它也可以跟其他值,如字符串,布尔值,数值以及普通函数

await会阻塞后面的代码,等主程序执行完,再回来执行。

async function a() {
  console.log("1");
  console.log("2");
}
a();
console.log("3");

async function b() {
  var c = await 10;
  console.log(c);
  console.log("one");
  console.log("two");
}
b();
console.log("three");
//1
//2
//3
//three
//10
//one
//two

async function async1 () {
  console.log('async1 start')
  await async2()
  console.log('async1 end') // 关键在这一步,它相当于放在 callback 中,最后执行
  // 类似于Promise.resolve().then(()=>console.log('async1 end'))
}

async function async2 () {
  console.log('async2')
}

console.log('script start')
async1()
console.log('script end')

// 打印
// script start
// async1 start
// async2
// script end
// async1 end
async function async1 () {
  console.log('async1 start') // 2
  await async2()

  // await后面的下面三行都是异步回调callback的内容
  console.log('async1 end') // 5 关键在这一步,它相当于放在 callback 中,最后执行
  // 类似于Promise.resolve().then(()=>console.log('async1 end'))
  await async3()
  
  // await后面的下面1行都是异步回调callback的内容
  console.log('async1 end2') // 7
}

async function async2 () {
  console.log('async2') // 3
}
async function async3 () {
  console.log('async3') // 6
}

console.log('script start') // 1
async1()
console.log('script end') // 4
async function async1 () {
  console.log('async1 start')
  await async2() // 这一句会同步执行,返回 Promise ,其中的 `console.log('async2')` 也会同步执行
  console.log('async1 end') // 上面有 await ,下面就变成了“异步”,类似 cakkback 的功能(微任务)
}

async function async2 () {
  console.log('async2')
}

console.log('script start')

setTimeout(function () { // 异步,宏任务
  console.log('setTimeout')
}, 0)

async1()

new Promise (function (resolve) { // 返回 Promise 之后,即同步执行完成,then 是异步代码
  console.log('promise1') // Promise 的函数体会立刻执行
  resolve()
}).then (function () { // 异步,微任务
  console.log('promise2')
})

console.log('script end')

// 同步代码执行完之后,屡一下现有的异步未执行的,按照顺序
// 1. async1 函数中 await 后面的内容 —— 微任务(先注册先执行)
// 2. setTimeout —— 宏任务(先注册先执行)
// 3. then —— 微任务

// 同步代码执行完毕(event loop - call stack被清空)
// 执行微任务
// 尝试DOM渲染
// 触发event loop执行宏任务

// 输出
// script start 
// async1 start  
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout

3、为什么async/await更好?

  • 使用async函数可以让代码简洁很多

  • 不需要像Promise一样需要then

  • 不需要写匿名函数处理Promise的resolve的值

  • 也不需要定义多余的data变量,还避免了嵌套代码

参考文章:

Promise async/await

promise和async用法及区别(详解)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值