一、异步代码的困境
1. 什么是单线程
01 - 概念
单线程 : 就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推
02 - js是单线程
js是单线程的,主要用途是与用户互动,以及操作DOM。
这决定了它只能是单线程
注 : JS的单线程并不是指整个JS引擎只有1个线程。它是指运行代码只有1个线程,但是它还有其他线程来执行其他任务。比如时间函数的计时、AJAX技术中的和后台交互等操作
假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准,所以规定同时只能操作一个东西
03 - 单线程的优点
优点 : 实现起来比较简单,执行环境相对单纯,一行一行代码执行下去即可
04 - 单线程的缺点
缺点 : 只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行
常见的情况有 :
- 浏览器无响应,可能程序死循环了
- 浏览器首次加载白屏,可能网络卡请求资源太慢
2. 什么是异步
立即执行后不是马上得到结果,比如 网络请求(如ajax)、定时器(setTimeout/setInterval),在可能发生等待的情况,不能阻挡住主线程的执行,因此,所有的“等待的情况”都需要异步
3. 回调函数
01 - 概念
回调函数 : 在调用setTimeout函数时,传递了一个函数进去,这个函数并没有立即被调用,而是在5秒后被调用。这种函数也被称为回调函数
02 - 配合异步操作
如果想要拿到异步操作后的结果或者是状态,可以使用回调函数
栗子一 🌰
function foo(fn) {
// 2. 执行代码
setTimeout(() => {
let result = 100 + 200;
// 3. 执行完成后,执行回调函数,把结果传递出去
fn(result);
}, 3000);
}
// 1. 传入一个函数,这个函数就叫做回调函数
foo((res) => {
console.log(res); // 300
});
栗子二 🌰
/**
* counter : 传入的参数
* successCallback : 成功执行的回调函数
* failureCallback : 失败执行的回调函数
*/
function execCode(counter, successCallback, failureCallback) {
// 异步任务
setTimeout(() => {
if (counter > 0) {
// counter可以计算的情况
let total = 0;
for (let i = 0; i < counter; i++) {
total += i;
}
// 在某一个时刻只需要回调传入的函数
successCallback(total);
} else {
// 失败情况, counter有问题
failureCallback(`${counter}值有问题`);
}
}, 3000);
}
// 传入三个参数
execCode(
100,
(value) => {
console.log('本次执行成功了:', value);
},
(err) => {
console.log('本次执行失败了:', err);
}
);
缺点 : 回调函数和参数需要同时传递,还需要确保位置没错,限制比较大
03 - 回调地狱
如果回调函数中又有回调函数,一层一层包裹下去的话~
栗子 🌰
需求 : 假如需要在3秒后吃饭,然后2秒后喝水,4秒后跑步,1秒后拉肚子
function foo(fn) {
// 第一步
setTimeout(() => {
console.log('吃饭');
// 第二步
setTimeout(() => {
console.log('喝水');
// 第三步
setTimeout(() => {
console.log('跑步');
// 第四步
setTimeout(() => {
console.log('拉肚子');
}, 1000);
}, 4000);
}, 2000);
}, 3000);
}
foo();
这还只是在代码量少的情况下,如果每一步操作都很多很复杂,其中又包含自己的回调函数,那么代码结构可想而知,馋不忍睹
二、Promise的简单使用
1. Promise的概念
Promise是一个类,可以翻译成 承诺、许诺 、期约
在通过new创建Promise对象时,需要传入一个回调函数,称之为executor
- 这个回调函数会被立即执行,并且给传入另外两个回调函数resolve、reject
- 当调用resolve回调函数时,会执行Promise对象的then方法传入的回调函数
- 当调用reject回调函数时,会执行Promise对象的catch方法传入的回调函数
Executor
Executor : 是创建Promise时需要传入的一个回调函数,这个回调函数会被立即执行,并且传入两个参数
通常是在Executor中确定Promise状态:
- 通过resolve,可以兑现(fulfilled)Promise的状态,也可以称之为已决议(resolved)
- 通过reject,可以拒绝(reject)Promise的状态
一旦状态被确定下来,Promise的状态会被 锁死,该Promise的状态是不可更改的
- 在调用resolve的时候,如果resolve传入的值本身不是一个Promise,那么会将该Promise的状态变成 兑现(fulfilled)
- 在之后再去调用reject时,已经不会有任何的响应了(并不是这行代码不会执行,而是无法改变Promise状态)
2. Promise的三种状态
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝
- 当执行executor中的代码时,处于该状态
- 已兑现(fulfilled): 意味着操作成功完成
- 执行了resolve时,处于该状态,Promise已经被兑现
- 已拒绝(rejected): 意味着操作失败
- 执行了reject时,处于该状态,Promise已经被拒绝
Promise的状态一旦被确定下来, 就不会再更改, 也不能再执行某一个回调函数来改变状态
// 1.创建一个Promise对象
const promise = new Promise((resolve, reject) => {
// 1.待定状态 pending
console.log("111111")
console.log("222222")
console.log("333333")
// 2.兑现状态 fulfilled
resolve()
// 3.拒绝状态 rejected
reject()
})
promise.then(value => {
console.log("成功的回调")
}).catch(err => {
console.log("失败的回调")
})
3. 使用Promise改造栗子二
function execCode(counter) {
// 1. 创建一个 promise 对象
const promise = new Promise((resolve, reject) => {
// 异步任务
setTimeout(() => {
if (counter > 0) {
// counter可以计算的情况
let total = 0;
for (let i = 0; i < counter; i++) {
total += i;
}
// 成功的回调,一执行就会马上去执行 .then 方法
resolve(total);
} else {
// 失败的回调,一执行就会马上去执行 .catch 方法
reject(`${counter}有问题`);
}
}, 3000);
});
// 2. 把该 promise 对象返回出去
return promise;
}
// 3. 接受 promise 对象
const promise = execCode(100)
// 4. 处理成功的回调
promise.then((value) => {
console.log("成功有了结果: ", value)
})
// 5. 处理失败的回调
promise.catch((err) => {
console.log("失败有了错误: ", err)
})
三、在Promise中使用resolve方法
情况一:如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数
情况二:如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态
情况三:如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据then方法的结果来决定Promise的状态
情况一 : 普通的值
const promise = new Promise((resolve, reject) => {
// 注意 : 方便演示,放到一起,其实只会执行一次resolve
resolve(123); // 123
resolve('123'); // '123'
resolve({ name: 'star' }); // { name: 'star'
resolve([1, 2, 3, 4, 5]); // [1, 2, 3, 4, 5]
});
promise.then((res) => {
console.log(res);
});
情况二 : promise对象
const p = new Promise((resolve, reject) => {
// 2. 会看这个promise对象中 执行的是什么状态
resolve({ name: 'resolve' });
// reject({ name: 'reject' });
});
const promise = new Promise((resolve, reject) => {
// 1. 传入promise对象
resolve(p);
});
promise
.then((res) => {
console.log(res); // { name: 'resolve' }
})
.catch((err) => {
console.log(err); // { name: 'reject' }
});
情况三 : thenable对象
const promise = new Promise((resolve, reject) => {
// 1. 传入对象,但是该对象中含有then方法
resolve({
name: 'star',
// 2. 会自动调用该then方法,同时传入一个resolve参数和reject
then(resolve, reject) {
// resolve(123);
reject(456);
}
});
});
promise
.then((res) => {
console.log(res); // 123
})
.catch((err) => {
console.log(err); // 456
});
四、在Promise中使用reject方法
传入的参数 无论是什么形态,都会直接作为reject状态的参数传递到catch,不区分参数
const promise = new Promise((resolve, reject) => {
// reject('failure'); // 失败的回调: failure
// reject(
// new Promise((reso) => {
// reso('123');
// })
// ); // 失败的回调: Promise {<fulfilled>: '123'}
reject({
then(res, rej) {}
}); // {then: ƒ}
});
promise.catch((err) => {
console.log('失败的回调:', err);
});
五、在Promise中使用then方法
1. then方法的使用
- then方法是Promise对象上的一个方法(实例方法)
- 其实是放在Promise的原型上的 Promise.prototype.then
then方法接受两个参数:
- fulfilled的回调函数:当状态变成fulfilled时会回调的函数
- reject的回调函数:当状态变成reject时会回调的函数
一个Promise的then方法是可以被多次调用的:
- 每次调用我们都可以传入对应的fulfilled回调
- 当Promise的状态变成fulfilled的时候,这些回调函数都会被执行
const promise = new Promise((resolve, reject) => {
resolve('success');
});
// then参数的传递方法:
// 1. 可以传递两个参数
// promise.then(res => {
// console.log("成功回调~", res)
// }, err => {
// console.log("失败回调~", err)
// })
// 2.也可以分开写
promise.then((res) => {}).catch((err) => {});
// 相当于监听了多个,每个都会相应
promise.then((res) => {
console.log('成功回调~', res);
});
promise.then((res) => {
console.log('成功回调~', res);
});
promise.then((res) => {
console.log('成功回调~', res);
});
promise.then((res) => {
console.log('成功回调~', res);
});
//但是如果调用的是reject,那么必须有捕获错误的回调,否则会报错
const p = new Promise((resolve, reject) => {
reject('fail');
});
p.then(
(res) => {
console.log('成功回调~', res);
},
(err) => {
// 必须有
console.log('失败回调~', err);
}
);
// 必须有
p.catch(() => {});
2. then方法的返回值
调用then方法后,默认会返回一个promise对象,这就是可以链式调用的原因
Promise有三种状态,那么这个Promise处于什么状态?
- 当then方法中的回调函数本身在执行的时候,那么它处于pending状态
- 当then方法中的回调函数返回一个结果时,那么它处于fulfilled状态,并且会将结果作为resolve的参数
- 情况一:返回一个普通的值
- 情况二:返回一个Promise对象
- 情况三:返回一个thenable对象
- 当then方法抛出一个异常时,那么它处于reject状态
const promise = new Promise((resolve) => {
resolve(123);
});
promise
.then((res) => {
console.log('first:', res); // first: 123
// 相当于返回undefined
// return resolve(undefined)
})
.then((res) => {
// 其实内部相当于是这么做的
return new Promise((resolve) => {
console.log('second:', res); // second: undefined
resolve(undefined);
});
})
.then((res) => {
console.log('three:', res); // three: undefined
});
01 - 返回普通值
const promise = new Promise((resolve) => {
resolve(111);
});
promise
.then((res) => {
console.log('first:', res); // first: 111
return 222;
})
.then((res) => {
console.log('second:', res); // second: 222
return [111, 222];
})
.then((res) => {
console.log('three:', res); // three: [111, 222]
});
02 - 返回新的promise对象
const promise = new Promise((resolve) => {
resolve(111);
});
promise
.then((res) => {
console.log('first:', res); // first: 111
/**
* 相当于resolve(new Promise),看上面的文章可知,当resolve一个新的promise对象时
* 会看当前新的promise的状态值,并等待其resolve|reject的值
*/
return new Promise((resolve, reject) => {
setTimeout(() => {
// resolve(222);
reject(333);
}, 3000);
});
})
.then((res) => {
console.log('success:', res); // success: 222
})
.catch((res) => {
console.log('fail:', res); // fail: 333
});
03 - 返回thenable对象
const promise = new Promise((resolve) => {
resolve(111);
});
promise
.then((res) => {
console.log('first:', res); // first: 111
/**
* 相当于resolve(thenable对象),看上面的文章可知,当resolve一个新的promise对象时
* 会去调当前对象的then方法,并有resolve, reject作为参数
*/
return {
then(resolve, reject) {
setTimeout(() => {
resolve(222);
// reject(333);
}, 3000);
}
};
})
.then((res) => {
console.log('success:', res); // success: 222
})
.catch((res) => {
console.log('fail:', res); // fail: 333
});
六、在Promise中使用catch方法
1. catch方法的使用
- catch方法也是Promise对象上的一个方法(实例方法):
- 它也是放在Promise的原型上的 Promise.prototype.catch
一个Promise的catch方法是可以被多次调用的:
- 每次调用都可以传入对应的reject回调
- 当Promise的状态变成reject的时候,这些回调函数都会被执行
const promise = new Promise((resolve, reject) => {
reject("failure")
})
promise.then(res => {
console.log("成功的回调:", res)
}).catch(err => {
console.log("失败的回调:", err)
})
promise.catch(err => {
console.log("失败的回调:", err)
})
promise.catch(err => {
console.log("失败的回调:", err)
})
promise.catch(err => {
console.log("失败的回调:", err)
})
promise.catch(err => {
console.log("失败的回调:", err)
})
2. catch方法的返回值
catch方法也是会返回一个Promise对象的,所以catch方法后面可以继续调用then方法或者catch方法
const promise = new Promise((resolve, reject) => {
reject('error: aaaaa');
// resolve('aaaaaa');
});
// 1.catch方法也会返回一个新的Promise
promise
.catch((err) => {
console.log('catch回调:', err);
// 默认会返回新的promise对象,resovle('bbbbb')
return 'bbbbb';
})
.then((res) => {
console.log('then第一个回调:', res);
return 'ccccc';
})
.then((res) => {
console.log('then第二个回调:', res);
});
3. 使用catch
一旦被reject或者报错,会去寻找最近的catch,中途不会执行then方法
const promise = new Promise((resolve, reject) => {
reject('error: aaaaa');
});
promise
.then(() => {
console.log('不会执行');
return 123;
})
.then(() => {
console.log('不会执行');
})
// 直接找到最近的catch执行
.catch((err) => {
console.log('catch回调被执行:', err); // catch回调被执行: error: aaaaa
// 默认返回undefined
})
// 会执行,因为catch也返回一个promise对象
.then(() => {
console.log('会执行!!!'); // 会执行!!!
});
4. 中途断裂
如果中途想执行reject或者报错了
const promise = new Promise((resolve, reject) => {
resolve(111);
});
promise
.then((res) => {
console.log('then第一次回调:', res); // then第一次回调: 111
return 222;
})
.then((res) => {
console.log('then第二次回调:', res); // then第二次回调: 222
throw new Error('第三个Promise的异常error');
})
.then(() => {
console.log('不会执行');
})
.catch((err) => {
console.log('catch回调被执行:', err); // catch回调被执行: 第三个Promise的异常error
// 默认返回undefined
return 333;
})
.then((res) => {
console.log('会执行', res); // 会执行 333
return new Promise((_, reject) => {
reject('reject');
});
})
.catch((err) => {
console.log('catch回调被执行:', err); // catch回调被执行: reject
});
七、在Promise中使用finally方法
finally是在ES9中新增的一个特性:表示无论Promise对象无论变成fulfilled还是rejected状态,最终都会被执行的代码。
finally方法是不接收参数的,因为无论前面是fulfilled状态,还是rejected状态,它都会执行
const promise = new Promise((resolve, reject) => {
resolve('aaaa');
// reject("bbbb")
});
promise
.then((res) => {
console.log('then:', res); // aaaa
})
.catch((err) => {
console.log('catch:', err); // bbbb
})
.finally(() => {
console.log('game over');
});
七、promise的类方法
上面文章中的then、catch、finally方法都属于Promise的实例方法
都是存放在Promise的prototype上的
1. Promise.resolve
Promise.resolve的用法相当于new Promise,并且执行resolve操作
promise.resolve('message');
// 相当于
new Promise((resolve) => {
resolve('message');
});
resolve参数的形态:
- 情况一:参数是一个普通的值或者对象
- 情况二:参数本身是Promise
- 情况三:参数是一个thenable
和上面的一样,就不写啦
2. Promise.reject
Promise.reject传入的参数 无论是什么形态,都会直接作为reject状态的参数传递到catch
const promise = Promise.reject("rejected error")
promise.catch(err => {
console.log("err:", err)
})
// 相当于
new Promise((_, reject) => {
reject("rejected error")
})
3. Promise.all
Promise..all : 将多个Promise包裹在一起形成一个新的Promise
新的Promise状态由包裹的所有Promise共同决定:
- 当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值组成一个数组
- 当有一个Promise状态为rejected时,新的Promise状态为rejected,并且会将第一个reject的返回值作为参数
全为fulfilled
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1 resolve');
}, 3000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 resolve');
}, 2000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3 resolve');
}, 5000);
});
// all:全部/所有
Promise.all([p1, p2, p3]).then((res) => {
console.log('all promise res:', res); // ['p1 resolve', 'p2 resolve', 'p3 resolve']
});
有一个为rejected
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('p1 reject error');
}, 3000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 resolve');
}, 2000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3 resolve');
}, 5000);
});
// all:全部/所有
Promise.all([p1, p2, p3])
.then((res) => {
console.log('all promise res:', res);
})
.catch((err) => {
// 3秒后直接来这里,其他的都不管了
console.log('all promise err:', err); // all promise err: p1 reject error
});
缺陷
- 当有其中一个Promise变成reject状态时,新Promise就会立即变成对应的reject状态
- 对于resolved的,以及依然处于pending状态的Promise,我们是获取不到对应的结果的
4. Promise.allSettled
该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是rejected时,才会有最终的状态
并且这个Promise的结果一定是fulfilled的
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p1 resolve")
reject('p1 reject error');
}, 3000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 resolve');
}, 2000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3 resolve');
}, 5000);
});
// 一定是成功的状态,直接调用then即可
Promise.allSettled([p1, p2, p3]).then((res) => {
// 5秒后打印
console.log('all settled:', res);
/**
* 会按照传参数的顺序打印
* [
* {status: 'rejected', reason: 'p1 reject error'} // 失败的信息
* {status: 'fulfilled', value: 'p2 resolve'} // 成功的信息
* {status: 'fulfilled', value: 'p3 resolve'} // 成功的信息
* ]
*/
});
5. Promise.race
- 如果其中一个Promise有了结果,最终的Promise的状态就是这个
- race是竞技、竞赛的意思,表示多个Promise相互竞争,谁先有结果,那么就使用谁的结果
- 不管是成功的还是失败的
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1 resolve');
// reject("p1 reject error")
}, 3000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 resolve');
// reject('p2 reject error');
}, 2000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3 resolve');
}, 5000);
});
// 特点: 会等到一个Promise有结果(无论这个结果是fulfilled还是rejected)
// 因为p2只用等2秒,它最快,不管它是成功还是失败,都用p2的值
Promise.race([p1, p2, p3])
.then((res) => {
console.log('race promise:', res); // race promise: p2 resolve
})
.catch((err) => {
console.log('race promise err:', err); // race promise err: p2 reject error
});
6. Promise.any
- 和race方法是类似
- any方法会等到一个fulfilled状态,才会决定新Promise的状态
- 如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态,会报一个AggregateError的错误
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p1 resolve")
reject('p1 reject error');
}, 3000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p2 resolve")
reject('p2 reject error');
}, 2000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p3 resolve")
reject('p3 reject error');
}, 5000);
});
// 类方法: any方法
Promise.any([p1, p2, p3])
.then((res) => {
// 一旦遇到一个resolve,就会来这里
console.log('any promise res:', res);
})
.catch((err) => {
// 全是reject,才会来这里
console.log('any promise err:', err); // any promise err: AggregateError: All promises were rejected
});
八、手写Promise
分步骤,一步一步完善代码
1. 实现状态的变化
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
/**
* 创建一个promise
*/
class StarPromise {
constructor(excute) {
// 定义状态
this._state = PENDING
// 定义值
this._value = undefined
try {
// 这里需绑定this,否则外界调用_resolve,_reject 会因为找不到this而报错
excute(this._resolve.bind(this), this._reject.bind(this))
} catch (error) {
// 捕获异常,报错自动_reject
this._reject(error)
}
}
/**
*
* @param {string} newState 新状态
* @param {any} value 值
*/
_changeState(newState, value) {
if (this._state !== PENDING) return
this._state = newState
this._value = value
}
// 成功的回调
_resolve(data) {
this._changeState(FULFILLED, data)
}
// 失败的回调
_reject(err) {
this._changeState(REJECTED, err)
}
}
const starPromise = new StarPromise((resolve, reject) => {
resolve(123)
// throw 123
})
console.log('starPromise', starPromise) // { _state: 'fulfilled', _value: 123 }
2. 创建微任务方法
// 创建一个微任务
const nextTick = (fn) => {
// 是node环境
if (process && process.nextTick) {
process.nextTick(fn)
} else {
// 不是node环境,setTimeout适用于其他环境,比如浏览器
setTimeout(fn, 0)
}
}
3. 核心代码
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 创建一个微任务
const nextTick = (fn) => {
// 是node环境
if (process && process.nextTick) {
process.nextTick(fn)
} else {
// 不是node环境,setTimeout适用于其他环境,比如浏览器
setTimeout(fn, 0)
}
}
// 判断是否是promise
const isPromise = (object) => {
return !!(object && typeof object === 'object' && typeof object.then === 'function')
}
/**
* 创建一个promise
*/
class StarPromise {
constructor(excute) {
// 定义状态
this._state = PENDING
// 定义值
this._value = undefined
// 处理函数形成的队列
this._handles = []
try {
// 这里需绑定this,否则外界调用_resolve,_reject 会因为找不到this而报错
excute(this._resolve.bind(this), this._reject.bind(this))
} catch (error) {
// 捕获异常,报错自动_reject
this._reject(error)
}
}
/**
* @param {string} newState 新状态
* @param {any} value 值
*/
_changeState(newState, value) {
if (this._state !== PENDING) return
this._state = newState
this._value = value
// 状态变化,执行队列中的函数
this._excuteHandles()
}
// 执行队列中的函数
_excuteHandles() {
// 如果状态是PENDING,不执行
if (this._state === PENDING) return
while (this._handles[0]) {
// 取出第一个处理函数,先进先出,执行完后删除
const handle = this._handles.shift()
// 执行函数
this._excuteHandle(handle)
}
}
// 执行函数
_excuteHandle({ state, fn, resolve, reject }) {
nextTick(() => {
// 判断状态是否与处理函数的状态一致
if (this._state !== state) return
// 判断是否有处理函数
if (typeof fn !== 'function') {
// 若不是函数,需要和之前的保持一致,沿用之前的数据
this._state === FULFILLED ? resolve(this._value) : reject(this._value)
return
}
try {
const result = fn(this._value)
// 判断是否是promise
if (isPromise(result)) {
// 这里传入的resolve和reject是新promise的resolve和reject,这样就可以实现链式调用
result.then(resolve, reject)
} else {
// 不是promise,直接返回
resolve(result)
}
} catch (error) {
reject(error)
}
})
}
// 成功的回调
_resolve(data) {
this._changeState(FULFILLED, data)
}
// 失败的回调
_reject(err) {
this._changeState(REJECTED, err)
}
/**
* 向处理队列中添加一个处理任务
* @param {String} state 状态
* @param {Function} fn 执行的函数
* @param {resolve} fn 当执行的函数执行成功后的回调
* @param {reject} fn 当函数执行失败后的回调
*/
_pushHandle(state, fn, resolve, reject) {
this._handles.push({ state, fn, resolve, reject })
}
/**
*
* @param {Function} onFilfilled 成功后调用的参数
* @param {Function} onRejected 失败后调用的参数
* @returns {StarPromise} 返回一个新的promise
*/
then(onFilfilled, onRejected) {
return new StarPromise((resolve, reject) => {
this._pushHandle(FULFILLED, onFilfilled, resolve, reject)
this._pushHandle(REJECTED, onRejected, resolve, reject)
this._excuteHandles()
})
}
/**
* 仅处理失败的回调,相当于then(null, onRejected)
* @param {Function} onRejected
*/
catch(onRejected) {
this.then(null, onRejected)
}
/**
* 无论成功或失败都会执行
* @param {funtion} onFinally
* @returns {StarPromise} 返回一个新的promise
*/
finally(onFinally) {
// 调用then方法,成功或失败都传入onFinally,这样就可以实现无论成功或失败都会执行
return this.then(
(data) => {
onFinally()
return data
},
(err) => {
onFinally()
throw err
}
)
}
}
const starPromise = new StarPromise((resolve, reject) => {
resolve(123)
// throw 123
})
starPromise
.then(
(data) => {
console.log('success', data)
return new StarPromise((resolve, reject) => {
resolve(456)
})
},
(err) => {
console.log('reject', err)
}
)
.then((data) => {
console.log('nextSuccess', data)
})
4. 静态方法
static resolve(data) {
if (data instanceof StarPromise) {
return data
}
return new StarPromise((resolve) => {
if (isPromise(data)) {
data.then(resolve)
} else {
resolve(data)
}
})
}
static reject(err) {
return new StarPromise((resolve, reject) => {
reject(err)
})
}