大试牛刀
// 前置知识
// @1: promise 在 pending 状态时,成功/失败回调只是在 EventTable 中注册,并没有
// 放进微任务队列
// @2: resolve/reject 方法只是更改了 promise 的状态,并把成功/失败回调保存了下来
// 并塞进微任务队列,并不会立即执行回调(异步执行的微任务)
// @3: 如果 then 方法 return 一个新的 promise,那么返回的新实例就是新的 promise
// 本例中没有 return,不然结果还会不一样
new Promise(resolve => {
console.log('promise1');
resolve();
}).then(() => {
console.log('then1');
new Promise(resolve => {
console.log('promise2');
resolve();
}).then(() => {
console.log('then21');
}).then(() => {
console.log('then22');
})
}).then(() => {
console.log('then12');
});
// promise1
// then1
// promise2
// then21
// then12
// then22
- 同步代码执行,输出 "promise1",并调用 resolve 把 promise 置为成功态。
- then1 整体代码作为微任务 then1 进入微任务队列,then12 到 EventTable 中注册,并等待 then1 返回结果。
- 全部同步代码执行完毕,扫描微任务队里中的任务,此时只有 then1,"then1" 被输出。
- then1 中初始化了一个新的 promise,promise 第一个参数(函数)被立即执行,输出 "promise2",并把 promise2 置为成功态。then21 入微任务队列,then22 到 EventTable 中注册并等待 then21 返回结果。
- 此时 then1 微任务执行完毕,then12 可以入微任务队列,并将 then1 从队列中移除。
- 扫瞄微任务队列,有两个待执行的微任务, 根据队列先进先出的特性,then21 先执行,然后 使得then22 入微任务队列,then12 后执行,输出 "then21"、"then22"。
- 扫描微任务队列,执行 then22,这就是执行的全部过程。
大试牛刀「加个 return」
new Promise(resolve => {
console.log('promise1');
resolve();
}).then(() => {
console.log('then1');
return new Promise(resolve => {
console.log('promise2');
resolve();
}).then(() => {
console.log('then21');
}).then(() => {
console.log('then22');
})
}).then(() => {
console.log('then12');
});
// promise1
// then1
// promise2
// then21
// then22
// then12
跟前面一道题的唯一区别是 then1 方法中多了一个 return,这个 return 直接导致了 then12 在等待 return 后面的值完全执行的返回结果,所以只有 then22 执行出队列后,then12 才能进微任务队列执行。
Promise.all
Promise.all 接收一个迭代器对象,要求里面的每一项都尽可能是个 promise 实例,返回一个新的 promise 实例,该实例是成功还是失败,取决于数组中的每一个 promise 实例是成功还是失败,只要有一个是失败的,返回结果的状态就是失败的,只有全部成功,结果的状态才是成功。
function fn(interval) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(interval);
}, interval);
});
}
let p1 = fn(3000); // 3s 后输出 3000
let p2 = fn(1000); // 1s 后输出 1000
let p3 = Promise.resolve(0); // 立即执行
Promise.all([p1, p2, p3]).then(results => {
// 不论谁先知道状态,最后结果的顺序和传递数组的顺序要保持一致
// 注意,results 是 promise 的成功回调参数,而不是返回值,所以是个数组
console.log(results); // 3s 后输出 [3, 1, 0]
}).catch(reason => {
// 处理过程中,遇到一个失败,则 All 立即失败,结果就是当前实例失败的原因
console.log(reason);
});
Promise.race
参数同 Promise.all,结果的状态和值取决于最先执行完毕的任务的状态。
Promise 解决的回调地狱
我们想让三个请求顺序执行:
const api1 = $.ajax({
url: '/api',
success(result) {
$.ajax({
url: '/api',
success(result) {
$.ajax({
url: '/api',
success(result) {
console.log('回调地狱');
}
})
}
})
}
})
我们拿 promise 来改造一下:
const api1 = () => {
return new Promise(resolve => {
$.ajax({
url: '/api1',
success(result1) {
resolve(result1);
}
});
});
}
const api2 = () => {
return new Promise(resolve => {
$.ajax({
url: '/api1',
success(result2) {
resolve(result2);
}
});
});
}
const api3 = () => {
return new Promise(resolve => {
$.ajax({
url: '/api1',
success(result3) {
resolve(result3);
}
});
});
}
// 串行
api1().then(result1 => {
return api2();
}).then(result2 => {
return api3();
}).then(result3 => {
});
// 并行
Promise.all([api1(), api2(), api3]).then(results => {
});