time: 2019.01.09
update: 2019.01.16
目录
1. Promise 对象上的方法
2. promise 原型上的方法
3. promise 错误处理
4. promise 特征
5. promise 应用
6. promise 模拟实现
创建 promise 中的代码会立即执行,then 内部任务属于 microtask 任务,会在本轮事件结束之前调用; 而 macrotask 会在下轮事件开始之前调用
了解 promise 所有特性,直接把它实现一次就行,或者看它的模拟实现了
// 解释一下下面代码的执行逻辑
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2
.then(result => console.log('123', result))
.catch(error => console.log(error))
// Error: fail
// 解释:此刻的 then 方法,都是针对在 p1 种返回的 promise 对象了,因为是 reject,所以直接走 catch 方法。
返回一个 promise, 参数同 Promise.all , 不同的是只要数组中某一个 promise 的状态变成 fulfilled 或 rejected ,那么返回的那个 promise 状态就随之改变
返回一个 promise ,传入参数有4种情况
返回一个 promise, promise 状态直接为 rejected, 传入的参数直接作为 catch 的参数函数的参数
因为 then 方法的第二个参数函数,通常用在 catch 来捕获了
const thenable = {
then(resolve, reject) {
reject('出错了');
}
};
Promise.reject(thenable)
.catch(e => {
console.log(e === thenable)
})
// true
了解特征,才能在实现原理上明白,为什么这么实现
resolve
和 reject
2个函数实现,分别对应 fullfilled 和 rejected 状态,状态改变之后不能再变resolve
和 reject
2个函数,其他 promise 实例不能使用这2个函数在常规使用中,通常我们不会使用构造函数 new Promise()
方式创建 promise 对象,而是直接使用某些具体的 api 来创建 promise 对象,比如 fetch 等方法
promise 对象的状态变化,可以在一定时间后 resolved ,也可以立即 resolved。
// 10s 后 resolved
const wait = time => new Promise(resolve => setTimeout(resolve, time || 10000))
// 立即 resolved
Promise.resolve().then()
const PENGDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';
// Promise 接受一个函数参数
function myPromise(callback) {
let that = this
this.statu = PENGDING;
this.fullfilledCallbackArray = []; // 保存 fullfilled 任务,当异步调用 resolve 时执行
this.rejectedCallbackArray = []; // 保存 rejeced 任务,当异步调用 reject 时执行
// 1 执行这个函数参数
callback(resolve, reject)
function resolve(value) {
// 2 如果返回的是一个 promise 对象,那么当前对象的状态就由该返回的 promise 对象决定了,因为直接传递的就是 resolve, reject 。如果返回的 promise 对象状态为 fullfilled ,那么当前 promise 对象状态就为 fullfilled,rejected 也一样。
if(value instanceof myPromise) {
return value.then(resolve, reject)
}
// 3. resolve 及 reject 内部异步执行,因为需要等待 then 的参数添加到任务队列中
setTimeout(() => {
that.statu = FULLFILLED;
that.result = value;
// resolve 异步执行的是 then 传入的方法
that.fullfilledCallbackArray.forEach(item => {
item(value)
})
})
}
function reject(reason) {
setTimeout(() => {
that.statu = REJECTED;
that.reason = reason;
that.rejectedCallbackArray.forEach(item => {
item(reason)
})
})
}
}
// 4 then 方法,返回一个新的 promise
myPromise.prototype.then = function (fullfilledCallback, rejectedCallback) {
const that = this; // 原 promise 对象的 this
return new myPromise((resolve, reject) => {
if(this.statu === FULLFILLED) {
// 原对象执行完毕,已经调用 resolve(),场景是没有链式调用,多是用在 promiseA+ 上面
setTimeout(() => {
let value = fullfilledCallback(that.result)
resolve(value)
})
} else if(this.statu === REJECTED && rejectedCallback) {
// 原对象执行完毕,已经调用 reject()
setTimeout(() => {
let value = rejectedCallback(that.reason)
reject(value)
})
} else if(this.statu === PENGDING) {
// 如果原对象还在执行过程中,还没有来得及调用 resolve() 或者 reject()
that.fullfilledCallbackArray.push((result) => {
let value = fullfilledCallback(result);
resolve(value)
});
that.rejectedCallbackArray.push(reason => {
let value = rejectedCallback(reason)
reject(value)
});
}
})
}
myPromise.prototype.catch = function (rejectedCallback) {
return this.then(null, rejectedCallback)
}
阮一峰 es 入门
mdn promise
mdn 使用 promises
mdn EventLoop
简书 Promise 详解与实现