1、constructor
起首我们都晓得Promise
有三个状况,为了轻易我们把它定义成常量
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
接下来我们来定义一个类
class MyPromise {
constructor(executor) {
//掌握状况,运用了一次以后,接下来的都不被运用
this.state = PENDING;
this.value = null;
this.reason = null;
// 定义resolve函数
const resolve = value => {
if (this.state === PENDING) {
this.value = value;
this.state = FULFILLED;
}
}
// 定义reject函数
const reject = value => {
if (this.state === PENDING) {
this.reason = value;
this.state = REJECTED;
}
}
// executor要领能够会抛出非常,须要捕捉
try {
// 将resolve和reject函数给运用者
executor(resolve, reject);
} catch (error) {
// 假如在函数中抛出非常则将它注入reject中
reject(error);
}
}
}
到这基础比较好明白我简朴申明一下
-
executor
:这是实例Promise
对象时在组织器中传入的参数,平常是一个function(resolve,reject){}
-
state:
`Promise的状况,一开始是默许的
pendding状况,每当挪用道
resolve和
reject要领时,就会转变其值,在背面的
then`要领中会用到 -
value
:resolv
e回调胜利后,挪用resolve
要领内里的参数值 -
reason
:reject
回调胜利后,挪用reject
要领内里的参数值 -
resolve
:声明resolve
要领在组织器内,经由过程传入的executor
要领传入个中,用以给运用者回调 -
reject
:声明reject
要领在组织器内,经由过程传入的executor
要领传入个中,用以给运用者回调
2、then
then
就是将Promise
中的resolve
或许reject
的效果拿到,那末我们就能够晓得这里的then要领须要两个参数,胜利回折衷失利回调,上代码!
then(onFulfilled, onRejected) {
if (this.state === FULFILLED) {
onFulfilled(this.value)
}
if (this.state === REJECTED) {
onRejected(this.reason)
}
}
我们来简朴的运转一下测试代码
const mp = new MyPromise((resolve, reject)=> {
resolve('******* i love you *******');
})
mp.then((suc)=> {
console.log(11111, suc);
}, (err)=> {
console.log('****** 你不爱我了*******', err)
})
// 11111 '******* i love you *******'
如许看着彷佛没有题目,那末我们来尝尝异步函数呢?
const mp = new MyPromise((resolve, reject)=> {
setTimeout(()=> {
resolve('******* i love you *******');
}, 0)
})
mp.then((suc)=> {
console.log(11111, suc);
}, (err)=> {
console.log('****** 你不爱我了*******', err)
})
我们会发明什么也没有打印,那里出题目了呢?原来是由于异步的缘由,当我们实行到then
的时刻this. state
的值还没发作转变,所以then
内里的推断就失效了。那末我们该怎样处理呢?
这就要说回典范得callback
了。来上源码
// 寄存胜利回调的函数
this.onFulfilledCallbacks = [];
// 寄存失利回调的函数
this.onRejectedCallbacks = [];
const resolve = value => {
if (this.state === PENDING) {
this.value = value;
this.state = FULFILLED;
this.onFulfilledCallbacks.map(fn => fn());
}
}
const reject = value => {
if (this.state === PENDING) {
this.value = value;
this.reason = REJECTED;
this.onRejectedCallbacks.map(fn => fn());
}
}
在then
内里增加
then(onFulfilled, onRejected) {
// ...
if(this.state === PENDING) {
this.onFulfilledCallbacks.push(()=> {
onFulfilled(this.value);
});
this.onRejectedCallbacks.push(()=> {
onRejected(this.value);
})
}
}
好了,到这异步的题目处理了,我们再来实行一下适才的测试代码。效果就出来了。到这我们还缺什么呢?
- 链式挪用
- 当我们不传参数时应该什么运转
这二个的思绪也都很简朴,链式挪用也就是说我们再返回一个promise
的实例就好了。而不传参则就是默许值的题目了。下面来看源码
then(onFulfilled, onRejected) {
let self = this;
let promise2 = null;
//处理onFulfilled,onRejected没有传值的题目
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : y => y
//由于毛病的值要让背面访问到,所以这里也要跑出个毛病,不然会在以后then的resolve中捕捉
onRejected = typeof onRejected === 'function' ? onRejected : err => {
throw err;
}
promise2 = new MyPromise((resolve, reject) => {
if (self.state === PENDING) {
console.log('then PENDING')
self.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(self.value);
console.log(333333, x, typeof x);
self.resolvePromise(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
}, 0)
});
self.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(self.reason);
self.resolvePromise(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
}, 0);
});
}
if (self.state === FULFILLED) {
console.log('then FULFILLED')
setTimeout(() => {
try {
let x = onFulfilled(self.value);
self.resolvePromise(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
}, 0);
}
if (self.state === REJECTED) {
console.log('then REJECTED')
setTimeout(() => {
try {
let x = onRejected(self.reason);
self.resolvePromise(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
})
}
});
return promise2;
}
为何表面要包一层setTimeout
?:由于Promise
自身是一个异步要领,属于微使命一列,必须得在实行栈实行完了在去取他的值,所以一切的返回值都得包一层异步setTimeout
。
resolvePromise
是什么?:这实际上是官方Promise/A+的需求。由于你的then
能够返回任何职,固然包含Promise
对象,而假如是Promise
对象,我们就须要将他拆解,直到它不是一个Promise
对象,取个中的值。
3、resolvePromise
我们直接看代码
resolvePromise(promise2, x, resolve, reject) {
let self = this;
let called = false; // called 防备屡次挪用
//由于promise2是上一个promise.then后的返回效果,所以假如雷同,会致使下面的.then会是同一个promise2,一向都是,没有终点
//相当于promise.then以后return了本身,由于then会守候return后的promise,致使本身守候本身,一向处于守候
if (promise2 === x) {
return reject(new TypeError('轮回援用'));
}
//假如x不是null,是对象或许要领
if (x !== null && (Object.prototype.toString.call(x) === '[object Object]' || Object.prototype.toString.call(x) === '[object Function]')) {
// x是对象或许函数
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, (y) => {
// 他人的Promise的then要领能够设置了getter等,运用called防备屡次挪用then要领
if (called) return;
called = true;
// 胜利值y有能够照样promise或许是具有then要领等,再次resolvePromise,直到胜利值为基础范例或许非thenable
self.resolvePromise(promise2, y, resolve, reject);
}, (reason) => {
if (called) return;
called = true;
reject(reason);
});
} else {
if (called) return;
called = true;
resolve(x);
}
} catch (reason) {
if (called) return;
called = true;
reject(reason);
}
} else {
// x是一般值,直接resolve
resolve(x);
}
}
- 为何要在一开始推断
promise2
和x
?:起首在Promise/A+中写了须要推断这两者假如相称,须要抛出非常,我就来解释一下为何,假如这两者相称,我们能够看下下面的例子,第一次p2
是p1.then
出来的效果是个Promise
对象,这个Promise
对象在被建立的时刻挪用了resolvePromise(promise2,x,resolve,reject)
函数,又由于x
即是其自身,是个Promise
,就须要then
要领递归它,直到他不是Promise
对象,然则x(p2)
的效果还在守候,他却想实行本身的then
要领,就会致使守候。 - 为何要递回去挪用
resolvePromise
函数?:置信仔细的人已发明了,我这里运用了递归挪用法,起首这是Promise/A+中请求的,其次是营业场景的需求,当我们遇到那种Promise
的resolve
里的Promise
的resolve
里又包了一个Promise
的话,就须要递归取值,直到x
不是Promise
对象。
4、catch
//catch要领
catch(onRejected){
return this.then(null,onRejected)
}
5、finally
finally
要领用于指定不论 Promise
对象末了状况怎样,都邑实行的操纵。该要领是 ES2018
引入规范的。
finally(fn) {
return this.then(value => {
fn();
return value;
}, reason => {
fn();
throw reason;
});
};
6、resolve/reject
人人一建都看到过Promise.resolve()
、Promise.reject()
这两种用法,它们的作用实在就是返回一个Promise对象,我们来完成一下。
static resolve(val) {
return new MyPromise((resolve, reject) => {
resolve(val)
})
}
//reject要领
static reject(val) {
return new MyPromise((resolve, reject) => {
reject(val)
})
}
7、all
all
要领能够说是Promise
中很经常使用的要领了,它的作用就是将一个数组的Promise
对象放在个中,当悉数resolve
的时刻就会实行then
要领,当有一个reject
的时刻就会实行catch
,而且他们的效果也是按着数组中的递次来排放的,那末我们来完成一下。
static all(promiseArr) {
return new MyPromise((resolve, reject) => {
let result = [];
promiseArr.forEach((promise, index) => {
promise.then((value) => {
result[index] = value;
if (result.length === promiseArr.length) {
resolve(result);
}
}, reject);
});
});
}
8、race
race方
法虽然不经常使用,然则在Promise
要领中也是一个能用得上的要领,它的作用是将一个Promise
数组放入race
中,哪一个先实行完,race
就直接实行完,并从then
中取值。我们来完成一下吧。
static race(promiseArr) {
return new MyPromise((resolve, reject) => {
promiseArr.forEach(promise => {
promise.then((value) => {
resolve(value);
}, reject);
});
});
}
9、deferred
static deferred() {
let dfd = {};
dfd.promies = new MyPromise((resolve, reject) => {
dfd.resolve = resolve;
dfd.rfeject = reject;
});
return dfd;
};
什么作用呢?看下面代码你就晓得了
let fs = require('fs')
let MyPromise = require('./MyPromise')
//Promise上的语法糖,为了防备嵌套,轻易挪用
//害处 毛病处理不轻易
function read(){
let defer = MyPromise.defer()
fs.readFile('./1.txt','utf8',(err,data)=>{
if(err)defer.reject(err)
defer.resolve(data)
})
return defer.Promise
}
10、测试
const mp1 = MyPromise.resolve(1);
const mp2 = MyPromise.resolve(2);
const mp3 = MyPromise.resolve(3);
const mp4 = MyPromise.reject(4);
MyPromise.all([mp1, mp2, mp3]).then(x => {
console.log(x);
}, (err) => {
console.log('err1', err);
})
MyPromise.race([mp1, mp4, mp2, mp3]).then(x => {
console.log(x);
}, (err) => {
console.log('err2', err);
})
var mp = new MyPromise((resolve, reject) => {
console.log(11111);
setTimeout(() => {
resolve(22222);
console.log(3333);
}, 1000);
});
mp.then(x => {
console.log(x);
}, (err) => {
console.log('err2', err);
})
//11111
//[ 1, 2, 3 ]
//1
//3333
//22222
假如有毛病或许不严谨的处所,请务必赋予斧正,非常谢谢。假如喜好或许有所启示,迎接 star,对作者也是一种勉励。