异步
允许程序在等待某些操作完成时继续执行其他任务,而不是阻塞或等待操作完成。
通俗讲就是一个任务不是连续完成的,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段;相应地,连续的执行就叫做同步。
任务执行后不会立即返回执行的结果,现在开始执行的行为,等待一段时间后完成
可以一起执行多个任务,如果任务 A 需要等待,可先执行任务 B,等到任务 A 结果返回后再继续回调
异步任务会在当前脚本的所有同步任务执行完才会执行
回调
可以简单理解为:(任务执行完)回(来)调(用)的函数
同步回调
异步回调
缺点
回调地狱:有一个异步获取数据的操作需要写一个回调函数,如果这个操作里又触发了另一个获取数据的操作,那么就需要在回调里嵌套回调,降低了代码的可读性,代码也越来越难管理
PromiseES6
- Promise 是一个构造函数,用来生成 Promise 实例
- Promise 接受一个【函数】作为参数,这个函数同时也包含两个函数参数(resolve,reject),这两个函数是回调函数,由 JavaScript 引擎提供
- Promise 构造函数里的 return 值会被忽略,也不会改变 Promise 的状态
Tip
new 一个 Promise 时,不需要调用它就会立即执行传入的函数,无法取消。如果不想立即执行,可以把它包在一个函数中,使用时调用那个函数即可
状态
Promise 的初始状态是 pending
- 调用 resolve(value) 会把 Promise 的状态置为
fulfilled
- 调用 reject(error) 会把 Promise 的状态置为
rejected
Note
- 一个 resolved 或 rejected 的 promise 都会被称为
settled
- resolve 或 reject 都只接受最多一个参数,其余的参数被忽略
- 只能调用一个 resolve 或一个 reject,其他的都会被忽略,任何状态的更改都是单向的,不会再变更
- resolve 或 reject 不会中断后面的代码,会继续执行,可以加 return 跳过后面的执行
then、catch、finally
当状态发生变化,后续的处理函数会执行的操作
then
- 它可以接受两个函数参数,第一个对应 resolve(),第二个对应 reject()
- then 方法也可以返回一个包含 then 方法的对象(thenable),它也会被当做一个 promise 来对待
- return 的值会由
Promise.resolve(return的返回值);
进行包装处理,因此不管回调函数中会返回一个什么样的值,最终 then 的结果都是返回一个新创建的 promise 对象
catch
- 该方法等同于 .then(null, onRejected),它只是一个简写形式
- 但是在执行 then 回调时如果遇到异常(代码出错),或者手动抛出异常(throw),会进入到 .catch() 里面,而不会进入到 then 的第二个回调里
then catch 的返回值
- 如果 then、catch 中没有对应状态的回调函数(或参数不是函数类型),那就会返回一个 与调用该方法的 Promise 相同的 新 Promise 对象(也就是向后传递)
- 如果手动返回一个 Promise,则返回 状态、值与之相同的新 Promise,其状态变更时,这个新的 Promise 也会变更
- 不管怎么样,返回的都是一个新的 Promise 实例,因此可以采用链式写法
finallyES2018
- 状态确定(settled)后执行,不管 Promise 对象最后状态如何,都会执行的操作,一般用于执行一些清理工作
- finally 函数没有参数,也不需要返回值(会被忽略)。它返回与调用该方法的 Promise 对象 相同的 新 Promise 对象
- finally 里抛出 error 时,执行将转到最近的 error 的处理程序
Promise 链
注意:多个 .then 添加到 Promise 上并不是 Promise 链,只是互不影响的并行关系:
错误处理
.catch 不仅捕获 reject() 抛出的错误,还会捕获 promise 中产生的语法错误或其他错误(promise 的处理程序周围有一个“隐式的 try..catch”,如果发生异常,它就会被捕获,并被视为 rejection 进行处理)
异步错误:
promise 的 catch 不能捕获异步产生的错误,这里的错误并不是在 executor 运行时生成的,而是在稍后生成的。因此 promise 无法处理它。需要改成:
Note
Promise 内部的错误不会影响到 Promise 外部的代码,也不会终止代码继续执行
主要用途
有异步操作时,使用 Promise 对这个异步操作进行封装(promise 可以按顺序进行编码,链式调用,更加具有可读性和灵活性)
缺点
- 无法取消 Promise,一旦新建它就会立即执行
- 当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
- 代码冗余,一眼看去一堆 then,原来的语义变得很不清楚
常用方法
Promise.all( iterable )
:并行执行多个 promise,全部 fulfilled 则 fulfilled;任意一个 rejected 立即 rejectedPromise.allSettled( iterable )
:所有的 promise 都 settled 则 fulfilledES2020Promise.race( iterable )
:只等待第一个 settled 的 promise 并获取其结果Promise.any( iterable )
:只等待第一个 fulfilled 的 promise 并获取其结果ES2021
很少使用 或 被 async 替代:
Promise.resolve( value )
:用结果 value 创建一个 resolved 的 promisePromise.reject( error )
:用 error 创建一个 rejected 的 promise
Promise.resolve(1) 可以认为是以下代码的语法糖:
Promise.reject(new Error(“出错了”)) 可以认为是以下代码的语法糖: