Promise是前端面试中的高频问题,大多数公司,都会问一些关于Promise的问题。
那是因为前端异步一直是老生常谈,promise更是绕不过去的话题,那么除了会使用promise之外,能否尝试自己封装一个promise呢?
如果你能根据PromiseA+的规范,写出符合规范的源码,那么我想,对于面试中的Promise相关的问题,都能够给出比较完美的答案。
Promise/A+规范地址
中文翻译地址
英文原版地址
先来看一下promise使用的一个小例子:
let p = new Promise((resolve, reject) => {
console.log('start')
resolve('jiaHang')
})
p.then((res) => {
console.log('success:' + res);
}, (err) => {
console.log('fail' + err);
})
console.log('end')
// 执行结果:start end success:jiaHang
看下文档翻译怎么解释Promise
由这个简单的例子和前2点的规范,我们可以归纳总结如下几点:
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class Promise {
constructor(executor) {
this.status = PENDING; // Promise状态,默认为pending
this.value = undefined;
this.reason = undefined;
let resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
}
}
executor(resolve, reject)
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
module.exports = Promise;
我们来测试下刚才自己写的Promise
const Promise = require('./promise')
let p = new Promise((resolve, reject) => {
console.log('start')
resolve('jiaHang')
})
p.then((res) => {
console.log('success:' + res);
}, (err) => {
console.log('fail' + err);
})
console.log('end')
// 执行结果:start success:jiaHang end
貌似结果看似对了,不过和原生的promise还是有不同的,就是success那条语句的打印顺序,不要急,后面我们会来慢慢实现。目前
还有一个问题要在这里先处理掉。
先看下下面这个
let p = new Promise((resolve, reject) => {
throw new Error('出错了')
console.log('start')
resolve('jiaHang')
})
p.then((res) => {
console.log('success:' + res);
}, (err) => {
console.log('fail' + err);
})
console.log('end')
执行时可能会发生异常,那要怎么处理呢,很简单,用try…catch将执行器给
包裹起来,如果执行器出错,那就内部将错误异常作为原因,让promise变成失败态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class Promise {
constructor(executor) {
this.status = PENDING; // Promise状态,默认为pending
this.value = undefined;
this.reason = undefined;
let resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
module.exports = Promise;
在不考虑执行顺序的前提下,一个简易版本的Promise就完成了,接下来让我们慢慢完善
还是来先看2个小例子
let p = new Promise((resolve, reject) => {
console.log('start')
setTimeout(() => {
resolve('jiaHang')
})
})
p.then((res) => {
console.log('success:' + res);
}, (err) => {
console.log('fail' + err);
})
console.log('end')
// 执行结果:start end success:jiaHang
想一下,Promise是怎么处理异步的呢?
let p = new Promise((resolve, reject) => {
console.log('start')
setTimeout(() => {
resolve('jiaHang')
})
})
p.then((res) => {
console.log('success:' + res);
}, (err) => {
console.log('fail' + err);
})
p.then((res) => {
console.log('success:' + res);
}, (err) => {
console.log('fail' + err);
})
console.log('end')
// 执行结果:start end success:jiaHang success:jiaHang
Promise 是怎么处理一个promise实例 可以then多次的?
基于这几点思考,我们的代码做以下改变:
// 省略其余等待,突出增加的点,等下发完整版
class Promise {
constructor(executor) {
...
this.resolveCallbacks = []; // 当then是pending 我希望把成功的方法都放到数组中
this.rejectCallbacks = []; // 当then是pending 我希望把失败的方法都放到数组中
let resolve = (value) => {
if (this.status === PENDING) {
...
this.resolveCallbacks.forEach(fn=>fn()); // 发布
}
}
let reject = (reason) => {
if (this.status === PENDING) {
...
this.rejectCallbacks.forEach(fn=>fn()); // 发布
}
}
...
}
then(onFulfilled, onRejected) {
...
if(this.status === PENDING){
// ... 先把成功的回调和失败的回调分开存放
this.resolveCallbacks.push(()=>{
onFulfilled(this.value)
});
this.rejectCallbacks.push(()=>{
onRejected(this.reason);
})
}
}
}
这样修改后,我们执行器方法中,有异步函数的情况时,p.then执行就会把对应的两个参数保存起来了。那么在什么时候调用呢?
答,肯定是在执行器中的resolve执行时候或者reject执行时候。多次调用then的时候,就会触发对应的成功和失败
完整的Promise代码如下:
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class Promise {
constructor(executor) {
this.status = PENDING; // Promise状态,默认为pending
this.value = undefined;
this.reason = undefined;
this.resolveCallbacks = []; // 当then是pending 我希望把成功的方法都放到数组中
this.rejectCallbacks = []; // 当then是pending 我希望把失败的方法都放到数组中
let resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.resolveCallbacks.forEach(fn=>fn()); // 发布
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.rejectCallbacks.forEach(fn=>fn()); // 发布
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
if(this.status === PENDING){
// ... 先把成功的回调和失败的回调分开存放
this.resolveCallbacks.push(()=>{
onFulfilled(this.value)
});
this.rejectCallbacks.push(()=>{
onRejected(this.reason);
})
}
}
}
module.exports = Promise;
换成自己写的Promise试下刚才的例子
const Promise = require('./promise')
let p = new Promise((resolve, reject) => {
console.log('start')
setTimeout(() => {
resolve('jiaHang')
})
})
p.then((res) => {
console.log('success:' + res);
}, (err) => {
console.log('fail' + err);
})
p.then((res) => {
console.log('success:' + res);
}, (err) => {
console.log('fail' + err);
})
console.log('end')
// // 执行结果:start end success:jiaHang success:jiaHang
这里为什么能拿到success的值,其关键点就在于发布订阅,then的时候,当status等于pending时候,将成功和失败的回调分别存到
对应的数组中,当触发resolve和reject的时候 触发对应的成功和失败。
接下来就是要实现Promise的链式调用,这个是Promise的核心
有如下场景,第一次读取的是文件名字,拿到文件名字后,再去读这个名字文件的内容。很显然这是两次异步操作,并且第二次的异步操作依赖第一次的异步操作结果。
// 简要说明 创建一个js文件 与这个文件同级的 name.txt, text.txt
// 其中name.txt内容是text.txt, 而text.txt的内容是 文本1
// node 运行这个js文件
let fs = require('fs')
fs.readFile('./name.txt', 'utf8', function (err, data) {
console.log(data)
fs.readFile(data, 'utf8', function (err, data) {
console.log(data)
})
})
很显然,上面的回调模式不是我们想要的,那么我们如何把上面写法给promise化呢?为了表述的更清晰一下,我还是分步来写:
function read(url){
return new Promise((resolve,reject)=>{
fs.readFile(url,'utf8',(err,data)=>{
if(err)reject(err);
resolve(data);
})
})
}
这个函数执行就会返回promise实例,也就是有then方法可以使用,我们有以下2种调用方式
readFile('./name.txt').then(
(data) => {
console.log(data)
readFile(data).then(
(data) => {
console.log(data)},
(err) => {
console.log(err)}
)
},
(err) => {
console.log(err)}
)
这种在回调中加回调,promise说你还不如不用我。
readFile('./name.txt')
.then(
(data) => {
console.log(data)
return readFile(data)
},
(err) => {
console.log(err)}
)
.then(
(data) => {
console.log(data) },
(err) => {
console.log(err) }
)
这种调用方式才是符合Promise的正确使用方式。
readFile('./name.txt')
.then(
(data) => {
console.log(data)
// return {'a': 100} // 1 返回引用类型
// return 100 // 2 返回基本类型
// return undefined 3 返回undefined
// 4 不写return
},
(err) => {
console.log(err)}
)
.then(
(data) => {
console.log(data) },
(err) => {
console.log(err) }
)
上面4种情况对应一下运行结果:
// text.txt {a: 100}
// text.txt 100
// text.txt undefined
// text.txt undefined
readFile('./name.txt')
.then(
(data) => {
console.log(data)
return new Promise(function(resolve, reject){
setTimeout(function(){
// resolve('ok')
reject('error')
},1000)
})
},
(err) => {
console.log(err)}
)
.then(
(data) => {
console.log(data) },
(err) => {
console.log(err) }
)
// 运行结果如下:
// resolve结果为: text.txt ok
// reject结果为: text.txt error
readFile('./name.txt')
.then(
(data) => {
console.log(data)
throw TypeError()
},
(err) => {
console.log(err)}
)
.then(
(data) => {
console.log(data) },
(err) => {
console.log(err) }
)
// 执行结果如下 text.txt err:TypeError
基于上面这些测试,以及 promise A+ 文档规范,我们可以总结出以下关于链式调用的几点:
then返回的是全新的promise
then(onFulfilled, onRejected) {
let promise2;
// 调用then后必须返回一个新的promise
promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
// 用try catch包裹是因为promise2 可能在运行的时候就出错了,如果出错直接reject出去即可
try{
// 需要对then的成功的回调和失败的回调取到他的返回结果,如果是普通值就让promise2成功即可
let x = onFulfilled(this.value);
resolve(x)
} catch (e) {
reject(e)
}
}
if (this.status === REJECTED) {
try{
let x = onRejected(this.reason)
resolve(x)
}catch (e) {
reject(e)
}
}
if(this.status === PENDING){
// ... 先把成功的回调和失败的回调分开存放
this.resolveCallbacks.push(()=>{
try{
let x = onFulfilled(this.value)
resolve(x)
}catch (e) {
reject(e)
}
});
this.rejectCallbacks.push(()=>{
try{
let x = onRejected(this.reason);
resolve(x)
}catch (e) {
reject(e)
}
})
}
})
return promise2
}
用上面的代码来测试下
const Promise = require('./promise')
let p = new Promise((resolve, reject) => {
console.log('start')
resolve('jiaHang')
// reject('jiaHang')
})
p.then((res) => {
console.log('success:' + res);
}, (err) => {
console.log('fail' + err);
}).then((res) => {
console.log('success:' + res);
}, (err) => {
console.log('fail' + err);
})
// 运行结果
// start
// success:jiaHang
// success:undefined
需要注意的是,需要对then的成功的回调和失败的回调取到到的返回结果进行处理,如果是普通值就让promise2成功即可
如果是promise 那应该让x这个promise执行 x.then。
我们将之前resolve(x)的地方替换成一个方法,统一处理这块的逻辑
if (this.status === FULFILLED) {
// 用try catch包裹是因为promise2 可能在运行的时候就出错了,如果出错直接reject出去即可
try{
// 需要对then的成功的回调和失败的回调取到他的返回结果
// 如果是普通值就让promise2成功即可
// 如果是promise 那应该让x这个promise执行 x.then
let x = onFulfilled(this.value);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e)
}
}
其他地方也是如此替换,我们单独写一个方法
let resolvePromise = (promise2,x,resolve,reject) => {
console.log(promise2);
}
思考下,这里能拿到promise2吗?为什么?其实目前是拿不到promise2的,打印结果为undefined。那怎么蔡才能拿到
其实规范2.2.4也说明了 要确保 onFulfilled 和 onRejected 方法异步执行(且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行) 所以要在resolve里加上setTimeout
then(onFulfilled, onRejected) {
let promise2;
// 调用then后必须返回一个新的promise
promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
// 2.2.4 规范
setTimeout(()=> {
// 用try catch包裹是因为promise2 可能在运行的时候就出错了,如果出错直接reject出去即可
try{
// 需要对then的成功的回调和失败的回调取到他的返回结果
// 如果是普通值就让promise2成功即可
// 如果是promise 那应该让x这个promise执行 x.then
let x = onFulfilled(this.value);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e)
}
}, 0)
}
if (this.status === REJECTED) {
setTimeout(()=> {
try{
let x = onRejected(this.reason)
resolvePromise(promise2,x,resolve,reject);
}catch (e) {
reject(e)
}
}, 0)
}
if(this.status === PENDING){
// ... 先把成功的回调和失败的回调分开存放
this.resolveCallbacks.push(()=>{
setTimeout(()=> {
try{
let x = onFulfilled(this.value)
resolvePromise(promise2,x,resolve,reject);
}catch (e) {
reject(e)
}
}, 0)
});
this.rejectCallbacks.push(()=>{
setTimeout(()=> {
try{
let x = onRejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
}catch (e) {
reject(e)
}
}, 0)
})
}
})
return promise2
}
来测试下,看下Promise2能有结果吗
const Promise = require('./promise')
let p = new Promise((resolve, reject) => {
console.log('start')
resolve('jiaHang')
// reject('jiaHang')
})
p.then((res) => {
console.log('success:' + res);
return new Promise((resolve, reject) => {
resolve(2)
})
}, (err) => {
console.log('fail' + err);
}).then((res) => {
console.log('success:' + res);
}, (err) => {
console.log('fail' + err);
})
结果为:
start
success:jiaHang
Promise {
status: 'pending',
value: undefined,
reason: undefined,
resolveCallbacks: [ [Function] ],
rejectCallbacks: [ [Function] ] }
可以看到promise2打印出来是一个Promise对象,接下来,我们把重心就可以放到来处理resolvePromise了。
resolvePromise函数处理
resolvePromise函数处理的情况有很多情况,我们也是一步步来处理,具体可以参考规范2.3
let p1 = new Promise((resolve, reject) => {
resolve();
})
let p2 = p1.then(() => {
return p2
})
先来看下执行的结果:
UnhandledPromiseRejectionWarning: TypeError: Chaining cycle detected for promise #
很明显,这是Promise报了一个类型错误,循环引用的问题,原因是p2的结果要等到p2执行完,自己等待自己,永远都是等待态。实际上开发中很少人会这样写,
但是所有的promise都遵循这个规范,不同的人写的promise可能会混用,尽可能考虑的周全 要考虑别人promise可能出错的情况。因此就有了如下代码:
let resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'))
}
}
// 看x是不是一个promise,promise应该是一个对象
if (typeof x === 'function' || (typeof x === 'object' && x !== null)) {
let called; // 表示是否调用过成功或者失败
// 尝试取当前x的then方法, 这个then方法可能别人定义的时候 用的Object.defineProperty
try {
let then = x.then; // 如果取then方法出错 那就用错误拒绝promise2
if (typeof then === 'function') {
// 我就认为他是一个promise
then.call(x, y => {
// 让当前的promise执行 ,不用多次取then方法了
// y 有可能还是一个promise , 继续调用resolvePromise方法,直到解析出一个常量为止,最终把常量传递下去
if (called) return; // 防止此方法多次被调用
called = true;
resolvePromise(promise2, y, resolve, reject);
}, r => {
if (called) return;
called = true;
reject(r); // 让当前的promise变成失败态即可
})
} else {
// x就是一个普通的对象 并没有then方法
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
// x肯定一个常量
resolve(x);
}
完整的resolvePromise如下:
let resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'))
}
// 看x是不是一个promise,promise应该是一个对象
if (typeof x === 'function' || (typeof x === 'object' && x !== null)) {
let called; // 表示是否调用过成功或者失败
// 尝试取当前x的then方法, 这个then方法可能别人定义的时候 用的Object.defineProperty
try {
let then = x.then; // 如果取then方法出错 那就用错误拒绝promise2
if (typeof then === 'function') {
// 我就认为他是一个promise
then.call(x, y => {
// 让当前的promise执行 ,不用多次取then方法了
// y 有可能还是一个promise , 继续调用resolvePromise方法,直到解析出一个常量为止,最终把常量传递下去
if (called) return; // 防止此方法多次被调用
called = true;
resolvePromise(promise2, y, resolve, reject);
}, r => {
if (called) return;
called = true;
reject(r); // 让当前的promise变成失败态即可
})
} else {
// x就是一个普通的对象 并没有then方法
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
// x肯定一个常量
resolve(x);
}
}
说明:这里边以下几点要注意
其实规范中也有说明,这里简单说下,用变量存储了一个指向 x.then 的引用,然后测试并调用该引用,
以避免多次访问 x.then 属性。这种预防措施确保了该属性的一致性,因为其值可能在检索调用时被改变。
called的标记是为了防止resolve,reject多次调用,不排除有人在resolve之后又调用reject。
到此,自己写的Promise可以算是完成,不过还有些问题要处理。先来看下下面这个用法:
let p = new Promise(function (resolve, reject) {
resolve(1000)
})
p.then().then().then(function (data) {
console.log(data, 'resolve');
}, function (error) {
console.log(error, 'reject');
})
我们的代码应该可以在then中什么都不传,实现值得穿透
所以在then方法中需要对接收的参数onFulfilled, onRejected进行容错处理,
onFulfilled 有就用原参数,没有就给个默认的函数 对于onRejected 没有就抛出异常
then(onFulfilled, onRejected) {
// onFulfilled, onRejected 是两个可选参数
// onFulfilled,返回val
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
// 如果onRejected不是函数就抛出异常
onRejected = typeof onRejected === 'function' ? onRejected : r => {
throw r};
let promise2;
// 调用then后必须返回一个新的promise
promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
// 2.2.4 规范
setTimeout(() => {
// 用try catch包裹是因为promise2 可能在运行的时候就出错了,如果出错直接reject出去即可
try {
// 需要对then的成功的回调和失败的回调取到他的返回结果
// 如果是普通值就让promise2成功即可
// 如果是promise 那应该让x这个promise执行 x.then
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)
}
if (this.status === PENDING) {
// ... 先把成功的回调和失败的回调分开存放
this.resolveCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)
});
this.rejectCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)
})
}
})
return promise2
}
至此,Promise可以算是比较完整的了,接下来我们用测试用例跑下试试。
npm install promises-aplus-tests -g
promises-aplus-tests 文件名
// 产生成功的promise
Promise.resolve = function (param) {
if (param instanceof Promise) {
return param;
}
return new Promise((resolve, reject) => {
if (param && param.then && typeof param.then === 'function') {
setTimeout(() => {
param.then(resolve, reject);
});
} else {
resolve(param);
}
});
}
// 产生一个失败的promise
Promise.reject = function(reason){
return new Promise((resolve,reject)=>{
reject(reason);
})
}
catch(rejectFunc){
return this.then(null,rejectFunc);
}
Promise.all = function(values){
return new Promise((resolve,reject)=>{
let results = []; // 结果数组
let i = 0;
let processData = (value,index)=>{
results[index] = value;
// 当成功的个数 和 当前的参数个数相等就把结果抛出去
if(++i === values.length){
resolve(results);
}
}
for(let i = 0 ; i< values.length;i++){
let current = values[i]; // 拿到数组中每一项
// 判断是不是一个promise
if((typeof current === 'object' && current !== null)|| typeof current == 'function'){
// 如果是promise
if(typeof current.then == 'function'){
// 就调用这个promise的then方法,把结果和索引对应上,如果任何一个失败了返回的proimise就是一个失败的promise
current.then(y=>{
processData(y,i);
},reject);
}else{
processData(current,i);
}
}else{
processData(current,i);
}
}
});
}
Promise.finally = function (callback) {
return this.then((value) => {
return Promise.resolve(callback()).then(() => {
return value;
});
}, (err) => {
return Promise.resolve(callback()).then(() => {
throw err;
});
});
}
至此,Promise以及其方法已全部实现。
完整代码如下:
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
let resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'))
}
// 看x是不是一个promise,promise应该是一个对象
if (typeof x === 'function' || (typeof x === 'object' && x !== null)) {
let called; // 表示是否调用过成功或者失败
// 尝试取当前x的then方法, 这个then方法可能别人定义的时候 用的Object.defineProperty
try {
let then = x.then; // 如果取then方法出错 那就用错误拒绝promise2
if (typeof then === 'function') {
// 我就认为他是一个promise
then.call(x, y => {
// 让当前的promise执行 ,不用多次取then方法了
// y 有可能还是一个promise , 继续调用resolvePromise方法,直到解析出一个常量为止,最终把常量传递下去
if (called) return; // 防止此方法多次被调用
called = true;
resolvePromise(promise2, y, resolve, reject);
}, r => {
if (called) return;
called = true;
reject(r); // 让当前的promise变成失败态即可
})
} else {
// x就是一个普通的对象 并没有then方法
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
// x肯定一个常量
resolve(x);
}
}
class Promise {
constructor(executor) {
this.status = PENDING; // Promise状态,默认为pending
this.value = undefined;
this.reason = undefined;
this.resolveCallbacks = []; // 当then是pending 我希望把成功的方法都放到数组中
this.rejectCallbacks = []; // 当then是pending 我希望把失败的方法都放到数组中
let resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.resolveCallbacks.forEach(fn => fn()); // 发布
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.rejectCallbacks.forEach(fn => fn()); // 发布
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
// onFulfilled, onRejected 是两个可选参数
// onFulfilled,返回val
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
// 如果onRejected不是函数就抛出异常
onRejected = typeof onRejected === 'function' ? onRejected : r => {
throw r};
let promise2;
// 调用then后必须返回一个新的promise
promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
// 2.2.4 规范
setTimeout(() => {
// 用try catch包裹是因为promise2 可能在运行的时候就出错了,如果出错直接reject出去即可
try {
// 需要对then的成功的回调和失败的回调取到他的返回结果
// 如果是普通值就让promise2成功即可
// 如果是promise 那应该让x这个promise执行 x.then
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)
}
if (this.status === PENDING) {
// ... 先把成功的回调和失败的回调分开存放
this.resolveCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)
});
this.rejectCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)
})
}
})
return promise2
}
catch(rejectFunc){
// catch的实现
return this.then(null,rejectFunc);
}
}
// 暴露一个方法这个方法需要返回一个对象 对象上需要有 promise resolve reject 三个属性
Promise.defer = Promise.deferred = function(){
let dfd = {
}
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
// 产生成功的promise
Promise.resolve = function (param) {
if (param instanceof Promise) {
return param;
}
return new Promise((resolve, reject) => {
if (param && param.then && typeof param.then === 'function') {
setTimeout(() => {
param.then(resolve, reject);
});
} else {
resolve(param);
}
});
}
// 产生一个失败的promise
Promise.reject = function(reason){
return new Promise((resolve,reject)=>{
reject(reason);
})
}
// all的原理
Promise.all = function(values){
return new Promise((resolve,reject)=>{
let results = []; // 结果数组
let i = 0;
let processData = (value,index)=>{
results[index] = value;
// 当成功的个数 和 当前的参数个数相等就把结果抛出去
if(++i === values.length){
resolve(results);
}
}
for(let i = 0 ; i< values.length;i++){
let current = values[i]; // 拿到数组中每一项
// 判断是不是一个promise
if((typeof current === 'object' && current !==null)|| typeof current == 'function'){
// 如果是promise
if(typeof current.then == 'function'){
// 就调用这个promise的then方法,把结果和索引对应上,如果任何一个失败了返回的proimise就是一个失败的promise
current.then(y=>{
processData(y,i);
},reject);
}else{
processData(current,i);
}
}else{
processData(current,i);
}
}
});
}
// race的原理
Promise.race = function(values){
return new Promise((resolve,reject)=>{
for(let i = 0 ; i< values.length;i++){
let current = values[i];
if((typeof current === 'object' && current !==null)|| typeof current == 'function'){
let then = current.then;
if(typeof then == 'function'){
// 比较哪个promise比较快,谁快用快
then.call(current,resolve,reject)
}else{
resolve(current);
}
}else{
resolve(current);
}
}
});
}
// finally的原理
// 不管成功还是失败,都会走到finally中,并且finally之后,还可以继续then。并且会将值原封不动的传递给后面的then.
Promise.finally = function (callback) {
return this.then((value) => {
return Promise.resolve(callback()).then(() => {
return value;
});
}, (err) => {
return Promise.resolve(callback()).then(() => {
throw err;
});
});
}
module.exports = Promise;