Promise学习总结

143 阅读6分钟

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。在处理promise问题的时候又绕不开async函数,在这之前又要知道事件循环(event loop),也就是代码执行的顺序。

(一)事件循环

1、宏任务和微任务

宏任务包括script 、setTimeoutsetInterval 、setImmediate 、I/O 、UI rendering
微任务包括: MutationObserverPromise.then()或catch()Promise为基础开发的其它技术,比如fetch APIV8的垃圾回收过程Node独有的process.nextTick(会插队)async函数中await后面的代码(下一行)

2、事件循环规则

  1. 一开始整个脚本作为一个宏任务执行;
  2. 同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列;
  3. 宏任务执行结束,检查微任务队列是否具有任务,有则依次执行,直到全部执行完;
  4. 执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空。

注意:同步代码直接放入执行栈,计时器是时间到了再放进异步队列。
执行顺序:执行宏任务,然后执行该宏任务产生的微任务,若微任务在执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。
记忆:1.同步代码->2.procsee.nextTick->3.微任务->4.宏任务->5.setImmediate

(二)Promise

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

特点:
1. Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),Promise对象状态的改变由自身异步操作的结果决定。
2. Promise对象的状态只能改变1次,且只有两种可能:从pending变为fulfilled和从pending变为rejected

1、基本使用:Promise对象是一个构造函数。

const promise = new Promise((resolve, reject) => {
  // 普通代码
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”,并将异步操作报出的错误,作为参数传递出去。

2、then()

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。这两个函数都是可选的,不一定要提供。它们都接受Promise对象传出的值作为参数。

3、catch()

catch()方法是.then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

4、finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

5、all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。全成功才成功,并返回一个数组;有一个失败返回最先失败的promise。

6、race()

Promise.race()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。返回最先结束的promise。

7、allSettled()

Promise.allSettled()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。返回所有内容。

8、any()

Promise.any()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。返回d第一个成功的。

9、resolve()和reject()

返回新的Promise实例,并更改状态。

** 总结 **

  1. Promise的状态一经改变就不能再改变。
  2. .then.catch都会返回一个新的Promise
  3. catch不管被连接到哪里,都能捕获上层未捕捉过的错误。
  4. Promise中,返回任意一个非 promise 的值都会被包裹成 promise 对象。
  5. Promise.then 或者 .catch 可以被调用多次, 但如果Promise内部的状态一经改变,并且有了一个值,那么后续每次调用.then或者.catch的时候都会直接拿到该值。
  6. .then 或者 .catchreturn 一个 error 对象并不会抛出错误,所以不会被后续的 .catch 捕获。
  7. .then.catch 返回的值不能是 promise 本身,否则会造成死循环。
  8. .then 或者 .catch 的参数期望是函数,传入非函数则会发生值透传。
  9. .then方法是能接收两个参数的,第一个是处理成功的函数,第二个是处理失败的函数,再某些时候你可以认为catch.then第二个参数的简便写法。
  10. .finally方法也是返回一个Promise,他在Promise结束的时候,无论结果为resolved还是rejected,都会执行里面的回调函数。
  11. Promise.all()的作用是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调。
  12. .race()的作用也是接收一组异步任务,然后并行执行异步任务,只保留取第一个执行完成的异步操作的结果,其他的方法仍在执行,不过执行结果会被抛弃。
  13. Promise.all().then()结果中数组的顺序和Promise.all()接收到的数组顺序一致。
  14. all和race传入的数组中如果有会抛出异常的异步任务,那么只有最先抛出的错误会被捕获,并且是被then的第二个参数或者后面的catch捕获;但并不会影响数组中其它的异步任务的执行。

(三)async和await

async函数异步代码同步化

  1. async函数返回一个Promise 对象,可以使用then方法添加回调函数。
  2. async函数内部抛出错误的时候,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被.then()方法的第二个回调函数接收或者.catch()方法回调函数接收到。
  3. await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。
  4. await的使用,必须要有async
  5. 写在await后面的代码放到async创建的那个Promise里面执行;写在await下面的代码放到前一个创建的那个Promise对象的.then里面执行。
async function fun(){
  return 1
}
console.log(fun());// Promise { 1 }

function fun2() {
  return new Promise((reslove)=>{
    reslove(1)
  })
}
console.log(fun2()); // Promise { 1 }

function fun3() {
  return Promise.resolve(1)
}

console.log(fun3()); // Promise { 1 }

所以async函数是promise的语法糖