前期准备
回调函数
同步回调函数
理解:立即执行,完全执行完之后才结束,不会方式回调队列中
列子:数组遍历forEach相关的回调函数
const arr = [1, 3, 5]
arr.forEach(item => { // 遍历回调,同步回调函数
console.log(item)
})
console.log('forEach()之后')
异步回调函数
理解:不会立即执行,放入任务队列,等待同步任务执行栈之后完成后调用任务队列中的回调函数才执行
列子:定时器回调、AJAX回调、promise的回调
Promise 是什么
表达:Promise是JS中进行异步变成的新解决方案
具体表达:从语法上,promise是一个构造函数;从功能上,promise对象用来封装一个异步操作并可以获取其结果。
一个Promise的三种状态
在开始使用Promise之前,我们首先需要了解Promise的三种状态:
- pending: 初始状态,既不是成功,也不是失败状态。
- fulfilled: 意味着操作成功完成。
- rejected: 意味着操作失败。
pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。
因为Promise.prototype.then和Promise.prototype.catch方法返回promise 对象, 所以它们可以被链式调用。
Promise的这三种状态有两个特点:
- 对象的状态不受外界影响。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。 - 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
Promise 基本用法
const p = new Promise((resolve, reject) => { // executor 执行器函数
// 执行异步操作代码
if(...) {
resolve(value); // 成功
} else {
reject(error); // 失败
}
Promise
构造函数接收一个函数作为参数,该函数的两个参数分别是resolve
和reject
。他们是两个函数,由JavaScript
引擎提供,不用自己部署。executor
执行器函数是带有 resolve
和 reject
两个参数的函数 。Promise
构造函数执行时立即调用executor
函数。resolve
函数的作用:当promise
对象的状态从pending
变为resovled
,在异步操作成功时调用,将异步操作结果作为参数传递出去。reject
函数的作用:当promise
对象的状态从pending
变为rejected
,在异步操作失败时调用,将异步操作错误信息作为参数传递出去。promise
实例对象生成后,可以用then
方法分别执行resolved
状态和rejected
状态的回调函数。then
方法可以接受两个回调函数作为参数。第一个回调函数是Promise
对象的状态变为resolved
时调用,第二个回调函数是Promise
对象的状态变为rejected
时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise
对象传出的值作为参数。
p.then((value) => { // onResolved
// success
}, (error) => { // onRejected
// failure
});
promise
新建后会立即执行构造器函数部分
let promise = new Promise((resolve, reject) => {
console.log('11'); // 会立即执行,同步回调函数,宏任务
resolve();
});
promise.then(() => {
console.log('22'); // 微任务
});
console.log('33');
// => 11
// => 33
// => 22
注意:调用resolve
或reject
并不会终结 Promise
的参数函数的执行。
new Promise((resolve, reject) => {
resolve(1); // 不影响
console.log(2);
}).then(r => {
console.log(r);
});
// 2
// 1
promise.then
返回的新promise
的结果状态有什么决定?
- 由
then
指定的回调函数执行的结果决定 - 如果抛出异常,新
promise
变为rejected
,reason
为抛出的异常 - 如果返回的是非
promise
的任意值,新promise
变为resolved
,value
为返回的值 - 如果返回的是另一个新
promise
对象,此promise
的结果就会成为下一个then
函数中新promise
的结果new Promise((resolve, reject) => {
resolve(1); // 不影响
console.log(2);
}).then(value => {
console.log('1', value);
return '111';
return Promise.resolve(3)
}).then(value => {
console.log('2',value);
// '111' // 获取到上一个then函数里面resolv回调函数中的 return 字符串 '111'
// 3 // 获取到上一个then函数里面resolv回调函数中的 return 的promise对象,成功值为3
})
promise 如何串联多个操作任务?
promise
的then()
方法返回一个信息的promise
,可以使用then()
的链式调用通过
then
的链式调用可以串联多个同步或者异步任务(异步任务需要返回promise
对象)new Promise((resolve, reject) => {
setTimeout(()=>{
console.log('执行任务1(异步)')
resolve(1)
}, 1000)
}).then(value =>{
console.log('任务1的结果 =>', value)
console.log('执行任务2(同步)')
return 2
}).then(value => {
console.log('任务2的结果 =>', value)
return new Promise((resolve, reject)=>{
// 启动任务3(异步)
setTimeout(()=>{
console.log('执行任务3(异步)')
resolve(3)
}, 1000)
})
}).then(value =>{
console.log('任务3的结果 =>', value)
})
// 执行任务1(同步)
// 任务1结果:1
// 执行任务2(同步)
// 任务2结果:2
// 执行任务3(异步)
// 任务3结果:3
promise异常穿透
当使用
promise
的then
链式调用时,可以在最后指定失败的回调- 前面任何操作出了异常,都会传到最后失败的回调中处理
中断promise链
- 当使用
promise
的then
链式调用时,在中间中断,不再调用后面的回调函数 - 方法:在回调函数中返回一个
pending
状态的promise
对象new Promise((resolve, reject) => {
setTimeout(()=>{
console.log('执行任务1(异步)')
resolve(1)
}, 1000)
}).then(value =>{
console.log('任务1的结果 =>', value)
console.log('执行任务2(同步)')
return 2
}).catch(reason => {
console.log('任务2的结果 =>', reason)
return new Promise(() => {})
// 返回一个状态为 pending的promise对象,中断 promise 链
// 后面的 then 方法也不会执行
}).then(value =>{
console.log('任务3的结果 =>', value)
})