由于想要更深刻学习promise,翻看了es6官方文档和一些人关于手写promise的一些博客,通过自己的理解手写了promise的一部分功能的源码,加深了自己对promise的理解
目录
1、基本用法
构造函数Promise的参数是一个函数,并且该函数有两个参数res和rej分别是Promise内置的函数,当生成一个Promise实例的时候,Promise的内置函数会立即执行,当函数中调用res和rej函数会改变当前promise的状态
let p1=new Promise((res,rej)=>{
if (Math.random()>0.5)){
resolve("成功");
} else {
reject("失败");
}
})
p1.then(res=>{
console.log(res) //当随机数大于0.5输出成功
},rej=>{
console.log(rej) //当随机数小于0.5 输出失败
})
2、基本功能源码
***注意调用resolve或reject并不会终结 Promise 的参数函数的执行。
function MyPromise(fn){
//首先需要将该构造函数传的参数(函数)立即执行,resolve,reject则是其中定义的函数
try{
fn(resolve,reject);
}catch (e) {
reject(e)
}
let self=this;
//定义当前对象的状态
this.state="pending";
this.data="";
//异步会调的函数集合
this.resArr=[];
this.rejArr=[];
//执行成功的函数,用于将其状态改为成功
function resolve(data){
//执行resolve时的状态必须是pending,才可被修改为成功
if(self.state === 'pending'){
self.state="resolve"
self.data=data;
//当new Promise实例时的内置函数是个异步操作的时候,不会立即改变他的状态,所以先将then定义的函数保存下来,状态改变后再触发
//let op=new MyPromise((res,rej)=>{
// setTimeout(function () {
// res("34354")
// },0)
//})
while (fn=self.resArr.shift()) {
// console.log(fn)
fn(data);
}
}
}
//执行失败的函数,用于将其状态改为失败
function reject(data){
//执行reject时的状态必须是pending,才可被修改为失败
if(self.state === 'pending') {
self.state='reject';
self.data=data;
//同上
while (fn=self.rejArr.shift()) {
// console.log(fn)
fn(data);
}
}
}
}
3、then函数源码
当修改完Promise实例的状态后,需要定义一个回调函数去处理成功或者失败的后续操作,then函数是定义在Promise的原型上
MyPromise.prototype.then=function(res,rej){
let self = this
if(self.state==='resolve') {
//函数变为异步操作
setTimeout(function (){
res(self.data)
},0)
}else if(self.state==='reject') {
//函数变为异步操作
setTimeout(function (){
rej(self.data)
},0)
}else if(self.state==="pending"){
//当new Promise实例时的内置函数是个异步操作的时候,不会立即改变他的状态,所以先将then定义的函数保存下来,状态改变后再触发
//let op=new MyPromise((res,rej)=>{
// setTimeout(function () {
// res("34354")
// },0)
//})
self.resArr.push(function(res){
return function(){
res(self.data)
}
}(res))
self.rejArr.push(function(rej){
return function(){
setTimeout(function (){
rej(self.data)
},0)
}
}(rej)) ;
}
}
4、then函数的链式调用
由于then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
前提是在then方法中用return返回
op.then(res=>{
return new MyPromise((res,rej)=>{
res("222promise")
})
}, rej=>{
return "sss"
}
).then(res=>{
console.log(res) //如果是成功状态则打印222promise
},rej=>{
console.log(rej)//如果是失败状态则打印sss
})
5、实现then的链式调用的源码
MyPromise.prototype.then=function(res,rej){
let self = this
//定义一个promise2实例最后return出去,通过判断上一个then的参数(函数)执行的的结果
//去判断如何触发promise2的resolve函数还是reject函数,实现链式操作
var promise2=new MyPromise((res2,rej2)=>{
if(self.state==='resolve') {
setTimeout(function (){
let returnValue=res(self.data)
//判断return出来的数据,实现不同逻辑
handleReturn(promise2,returnValue,res2,rej2)
},0)
}else if(self.state==='reject') {
setTimeout(function (){
let returnValue= rej(self.data)
//判断return出来的数据,实现不同逻辑
handleReturn(promise2,returnValue,res2,rej2)
},0)
}else if(self.state==="pending"){
self.resArr.push(function(res){
return function(){
let returnValue=res(self.data)
//判断return出来的数据,实现不同逻辑
handleReturn(promise2,returnValue,res2,rej2)
}
}(res))
self.rejArr.push(function(rej){
return function(){
setTimeout(function (){
let returnValue= rej(self.data)
//判断return出来的数据,实现不同逻辑
handleReturn(promise2,returnValue,res2,rej2)
},0)
}
}(rej)) ;
}
})
return promise2
}
//@promise2:then函数最终要return出去的promise实例
//@returnValue:then函数中的参数(函数)执行return出的结果
//@res2,rej2:promise2中用来触发成功或失败的函数
function handleReturn(promise2,returnValue,res2,rej2){
//判断return出来的数据是否是promise实例,是则先接受成功(失败)返回的结果,再触发下一个链式
if(returnValue instanceof MyPromise){
returnValue.then(res=>{
res2(res)
},rej=>{
rej2(rej)
})
}else{
//如果是原始值的话,则原样返回
res2(returnValue)
}
}
6、promise的状态影响
resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例,比如像下面这样。
let op1=new MyPromise((res,rej)=>{
res("222")
})
let op=new MyPromise((res,rej)=>{
res(op1)
})
op.then(res=>{
console.log(res) //打印222
},rej=>{
})
7、promise状态影响源码
Promise构造函数中改变状态时多加一层判断
function resolve(data){
//判断resolve参数是否是promise实例,必须先获取到上一个promise实例状态变化后,将数据传给后续操作
if(data instanceof MyPromise){
data.then(res=>{
resolve(res)
},rej=>{
reject(rej)
})
return
}
if(self.state === 'pending'){
self.state="resolve"
self.data=data;
// console.log(self.resArr)
while (fn=self.resArr.shift()) {
// console.log(fn)
fn(data);
}
}
}
8、完整源码
function MyPromise(fn){
let self=this;
//定义当前对象的状态
this.state="pending";
this.data="";
//异步会调的函数集合
this.resArr=[];
this.rejArr=[];
//执行成功的函数,用于将其状态改为成功
function resolve(data){
if(data instanceof MyPromise){
data.then(res=>{
resolve(res)
},rej=>{
reject(rej)
})
return
}
//执行resolve时的状态必须是pending,才可被修改为成功
if(self.state === 'pending'){
self.state="resolve"
self.data=data;
//当new Promise实例时的内置函数是个异步操作的时候,不会立即改变他的状态,所以先将then定义的函数保存下来,状态改变后再触发
//let op=new MyPromise((res,rej)=>{
// setTimeout(function () {
// res("34354")
// },0)
//})
while (fn=self.resArr.shift()) {
// console.log(fn)
fn(data);
}
}
}
//执行失败的函数,用于将其状态改为失败
function reject(data){
if(self.state === 'pending') {
self.state='reject';
self.data=data;
while (fn=self.rejArr.shift()) {
// console.log(fn)
fn(data);
}
}
}
//首先需要将该构造函数传的参数(函数)立即执行,resolve,reject则是其中定义的函数
try{
fn(resolve,reject);
}catch (e) {
reject(e)
}
}
//判断return出来的数据,实现不同逻辑
//@promise2:then函数最终要return出去的promise实例
//@returnValue:then函数中的参数(函数)执行return出的结果
//@res2,rej2:promise2中用来触发成功或失败的函数
function handleReturn(promise2,returnValue,res2,rej2){
//判断return出来的数据是否是promise实例,是则先接受成功(失败)返回的结果,再触发下一个链式
if(returnValue instanceof MyPromise){
returnValue.then(res=>{
res2(res)
},rej=>{
rej2(rej)
})
}else{
res2(returnValue)
}
}
MyPromise.prototype.then=function(res,rej){
let self = this
//定义一个promise2实例最后return出去,通过判断上一个then的参数(函数)执行的的结果
//去判断如何触发promise2的resolve函数还是reject函数,实现链式操作
var promise2=new MyPromise((res2,rej2)=>{
if(self.state==='resolve') {
//函数变为异步操作
setTimeout(function (){
let returnValue=res(self.data)
handleReturn(promise2,returnValue,res2,rej2)
},0)
}else if(self.state==='reject') {
//函数变为异步操作
setTimeout(function (){
let returnValue= rej(self.data)
handleReturn(promise2,returnValue,res2,rej2)
},0)
}else if(self.state==="pending"){
//当new Promise实例时的内置函数是个异步操作的时候,不会立即改变他的状态,所以先将then定义的函数保存下来,状态改变后再触发
//let op=new MyPromise((res,rej)=>{
// setTimeout(function () {
// res("34354")
// },0)
//})
self.resArr.push(function(res){
return function(){
let returnValue=res(self.data)
handleReturn(promise2,returnValue,res2,rej2)
}
}(res))
self.rejArr.push(function(rej){
return function(){
setTimeout(function (){
let returnValue= rej(self.data)
handleReturn(promise2,returnValue,res2,rej2)
},0)
}
}(rej)) ;
}
})
return promise2
}