使用js实现Promise

一、什么是promise

Promise的出现,原本是为了解决回调地狱的问题。以我们平常使用的ajax请求为例:

传统js方法:

getData(method, url, successFun, failFun){
  var xmlHttp = new XMLHttpRequest();
  xmlHttp.open(method, url);
  xmlHttp.send();
  xmlHttp.onload = function () {
    if (this.status == 200 ) {
      successFun(this.response);
    } else {
      failFun(this.statusText);
    }
  };
  xmlHttp.onerror = function () {
    failFun(this.statusText);
  };
}

使用Promise:

getData(method, url){
  var promise = new Promise(function(resolve, reject){
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open(method, url);
    xmlHttp.send();
    xmlHttp.onload = function () {
      if (this.status == 200 ) {
        resolve(this.response);
      } else {
        reject(this.statusText);
      }
    };
    xmlHttp.onerror = function () {
      reject(this.statusText);
    };
  })
  return promise;
}

getData('get','www.xxx.com').then(successFun, failFun)

很显然,我们把异步中使用回调函数的场景改为了.then().catch()等函数链式调用的方式。基于promise我们可以把复杂的异步回调处理方式进行模块化。

大致Promise的结构可以分成如下:

Promise构造函数接受一个函数作为参数,函数里面有两个参数resolve和reject分别作为执行成功或者执行失败的函数
var promise=new Promsie(function(resolve,rejec){
    if(/*异步执行成功*/){
        resolve(value);
    }else{
        reject(error);
    }
})
通过then设置操作成功之后的操作,接受两个函数作为参数,第一个成功的操作必写,第二个失败后的操作可选
promise.then(function(){
    //回调执行成功之后的操作
},function(){
    //回调执行失败之后的操作,可选
});

熟悉了Promise的结构后我们要了解一下Promise构造函数的一些属性和方法,可以看出,

Promise有三种状态:

1、pending(异步操作未完成的状态)

2、resolved(异步操作成功的状态)

3、rejected(异步操作失败的状态)

两种方法:

1.resolve()

2.reject()

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

当然Promise实例生成后还能再调用一种方法:

then()

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

了解好这些后我们就可以自己来写一个简单的Promise构造函数了

二、js实现Promise

我将自己写的构造函数命名为NewPromise

class NewPromise {
    constructor(executor) {
        if (typeof executor !== 'function') {
            throw new Error('Executor must be a function');
        }
        this.state = 'pending';
        const resolve = res => {
            if (this.state !== 'pending') {
                return;
             }
             this.state = 'resolved';
             this.internalValue = res;
        };
        const reject = err => {
             if (this.state !== 'pending') {
                 return;
             }
             this.state = 'rejected';
             this.internalValue = err;
        };
        try {
             executor(resolve, reject);
        } catch (err) {
             reject(err);
        }
    }
  
    then(onResolved, onRejected) {
        if (this.state === 'resolved') {
             onResolved(this.internalValue);
        } else if (this.$state === 'rejected') {
             onRejected(this.internalValue);
        } 
     }
}


let p = new NewPromise(resolve => {
	resolve('Hello');
});
p.then(res => console.log(res)); //Hello

看起来好像没啥问题,但是仔细观察便能知道我们并没有处理如果在调用的时候状态还是pending的情况,比如我们使用setTimeout函数:                                                                                                                                                                      

let p = new NewPromise(resolve => {
	// resolve('Hello');
 	setTimeout(() => resolve('Hello'), 100);
});
p.then(res => console.log(res));

这个时候可以看到控制台没有任何输出。这要怎么解决呢,我们可以使用一个变量来存储,当Promise状态还是pending的时候,我们就将onResolved和onRejected存储到这个变量中,当执行完Promise之后再来调用它。代码如下:


class NewPromise {
 	constructor(executor) {
	 	if (typeof executor !== 'function') {
	 	 	throw new Error('Executor must be a function');
 		}
	 	this.state = 'pending';
	 	this.statesSave = [];
	 	const resolve = res => {
		 	if (this.state !== 'pending') {
		 		return;
	 		}
 			this.state = 'resolved';
		 	this.internalValue = res;
		 	for (const { onResolved } of this.statesSave) {
		 		onResolved(res);
		 	}
		 };
	 	const reject = err => {
		 	if (this.state !== 'pending') {
		 		return;
		 	}
		 	this.state = 'rejected';
		 	this.internalValue = err;
		 	for (const { onRejected } of this.statesSave) {
		 		onRejected(err);
		 	}
	 	};
	 	try {
	 	 executor(resolve, reject);
	 	} catch (err) {
	 	 reject(err);
	 	}
 	}
  
	then(onResolved, onRejected) {
		if (this.state === 'resolved') {
	 		onResolved(this.internalValue);
		} else if (this.$state === 'rejected') {
	 		onRejected(this.internalValue);
		} 
		else {
	 	    this.statesSave.push({ onResolved, onRejected });
	 	}
	}
}


let p = new NewPromise(resolve => {
	// resolve('Hello');
 	setTimeout(() => resolve('Hello'), 3000);
});
p.then(res => console.log(res));//Hello

这时候控制台就在3s之后输出Hello了

以上就是使用js实现Promise的过程了,部分内容是借鉴网上查找的资料如有雷同请见谅,谢谢



你可能感兴趣的:(JavaScript)