欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

es6 Promise的简单实现

程序员文章站 2022-06-30 19:13:12
...

需求分析

  1. Promise接受一个callback进行异步操作,callback接受两个方法参数resolve, reject
  2. then方法:
    a. then方法接受一个callback方法
    b. then以后可以继续调用then, 并将上次的then 的callback返回的值传递给下一个then的callback
    c. then的执行需要发生在resolve之后
  3. catch方法,捕获异常处理:
    a. reject方法需要调用
    b. 其他地方

动手

1. 需求一, Promise的构造

function MyPromise(cb) {
	cb(this.resolve.bind(this), this.reject.bind(this));
}

MyPromise.prototype.resolve = function(result) { ... }

MyPromise.prototype.reject = function(err) { ... }

2. 需求二, then的处理

2.1. 基于2a和2b的需求,可以解析为then传入的callback需要有地方存放,存放起来后等待构造函数的callbak执行后响应执行。

function MyPromise(cb) {
	this.thenCallbacks = [];
	cb(this.resolve.bind(this), this.reject.bind(this));
}

MyPromise.prototype.resolve = function(result) { ... }

MyPromise.prototype.reject = function(err) { ... }

MyPromise.prototype.then = function(cb) {
	this.thenCallbacks.push(cb);
	return this; // 返回自身以备多次调用
}

2.2. 需要提供方法来执行then的所有callback

function MyPromise(cb) {
	this.result = null; // 临时存放resolve或者每次then callback后的结果
	this.thenCallbacks = [];
	cb(this.resolve.bind(this), this.reject.bind(this));
}

MyPromise.prototype.resolve = function(result) { ... }

MyPromise.prototype.reject = function(err) { ... }

MyPromise.prototype.then = function(cb) {
	this.thenCallbacks.push(cb);
	return this; // 返回自身以备多次调用
}

MyPromise.prototype.handleThen = function) {
	this.thenCallbacks.forEach((cb) => {
		this.result = cb(result);
	})
	return this.result; // 将最后结果返回
}

2.3. 在resolve以后调用handleThen, 并且确保handleThen执行在所有then调用之后

function MyPromise(cb) {
	this.result = null; // 临时存放resolve或者每次then callback后的结果
	this.thenCallbacks = [];
	cb(this.resolve.bind(this), this.reject.bind(this));
}

MyPromise.prototype.resolve = function(result) { 
	this.result = result;
	setTimeout(() => this.handleThen(), 0); // 放入调用栈底
}

MyPromise.prototype.reject = function(err) { ... }

MyPromise.prototype.handleThen = function() {
	this.thenCallbacks.forEach((cb) => {
		this.result = cb(result); // 每次将cb的返回值存起来,以备下一次调用
	})
	return this.result; // 将最后结果返回
}

3. 需求三,catch的处理

3.1 由于catch是一次性的,只需在调用的时候先存起来, 以及后面的执行方法

...

MyPromise.prototype.catch = function(cb) {
	this.catchCallback = cb;
}

MyPromise.prototype.handleCatch = function(err) {
	this.catchCallback && this.catchCallback(err);
}

3.2 需要处理Promise的reject方法

...
MyPromise.prototype.reject = function(err) {
	setTimeout(() => this.handleCatch(err), 0); // 确保最后调用
}
...

3.3 还需要处理Promise回掉过程中产生的错误

function MyPromise(cb) {
	this.result = null; // 临时存放resolve或者每次then callback后的结果
	this.thenCallbacks = [];
	this.catchCallback = null;
	try {
		cb(this.resolve.bind(this), this.reject.bind(this));
	} catch(err) {
		this.handleError(err);
	}
}
...

3.4 还有then过程中的错误

...
MyPromise.prototype.handleThen = function() {
	try {
		this.thenCallbacks.forEach((cb) => {
			this.result = cb(result); // 每次将cb的返回值存起来,以备下一次调用
		})
	} catch(err) {
		setTimeout(() => this.catchCallback(err), 0); // 确保最后调用
	}
	return this.result; // 将最后结果返回
}
...

至此,基本功能已经实现,完整代码:

function MyPromise(cb) {
	this.result = null; // 临时存放resolve或者每次then callback后的结果
	this.thenCallbacks = [];
	this.catchCallback = null;
	try {
		cb(this.resolve.bind(this), this.reject.bind(this));
	} catch(err) {
		this.handleError(err);
	}
}

MyPromise.prototype.resolve = function(result) { 
	this.result = result;
	setTimeout(() => this.handleThen(), 0); // 放入调用栈底
}

MyPromise.prototype.reject = function(err) {
	setTimeout(() => this.handleCatch(err), 0); // 确保最后调用
}

MyPromise.prototype.then = function(cb) {
	this.thenCallbacks.push(cb);
	return this; // 返回自身以备多次调用
}

MyPromise.prototype.catch = function(cb) {
	this.catchCallback = cb;
}

MyPromise.prototype.handleThen = function() {
	try {
		this.thenCallbacks.forEach((cb) => {
			this.result = cb(result); // 每次将cb的返回值存起来,以备下一次调用
		})
	} catch(err) {
		setTimeout(() => this.catchCallback(err), 0); // 确保最后调用
	}
	return this.result; // 将最后结果返回
}

MyPromise.prototype.handleCatch = function(err) {
	this.catchCallback && this.catchCallback(err);
}

最后测试以下

new MyPromise((resolve, reject) => {
		setTimout(() => resolve(3), 1000);
	})
	.then((result) => {
		result += result
		console.log('first call', result)
		return reulst
	})
	.then((result) => {
		result *= result
		console.log('second call', result)
		return reulst
	})
	.catch((err) => console.log(err))

// 结果
// 1s delay
// first call 6
// second call 36