手动实现一个Promise,简洁明了

JS版本中,更新最大的一个版本就是ES6了,包括了const、let、模板字符串、箭头函数、类、Generator、Promise等等一系列语法糖。

在ES7没出来前,Promise是代替传统回调的主要方式,ES7后更多的是使用async-await,但Pomise的使用仍不在少数

本文章,我们一起实现一个Promise,你可能说,我直接用它就行了,干嘛自己写一个。非也,在我看来,理解代码思想才是核心,这能大大提高我们的js书写功底。

下面我们进入正题:

传参:用then传入成功或失败时执行的回调,用catch传入异常时执行的回调。

返回:都返回promise实例,以实现链式调用。

编写代码:

class MyPromise 

	constructor(fn) {
		this.doneList = [];
		this.failList = [];
		this.catchCb = function() {};
		setTimeout(() => {
			try {
				fn(this.resolve.bind(this), this.reject.bind(this));
			} catch (e) {
				this.catchCb(e);
			}
		}, 0)
	}
	// 将 .then里的第一个参数加入到成功队列
	done(success) {
		if(typeof success === "function") {
			this.doneList.push(success )
		} else {
			throw new Error("传入success的参数必须为function!");
		}
		return this;
	}
	// 将 .then里的第二个参数加入到失败队列
	fail(fail) {
		if(typeof fail === "function") {
			this.failList.push(fail )
		} else {
			throw new Error("传入fail的参数为必须为function!");
		}
		return this;
	}
	// 成功时,遍历成功队列,执行里面的所有函数
	resolve(res) {
		this.doneList.forEach(fn => {
			fn(res);
			this.doneList.shift();
		})
	}
	// 成功时,遍历失败队列,执行里面的所有函数
	reject(err) {
		this.failList.forEach(fn => {
			fn(err);
			this.failList.shift();
		})
	}
	// 将 .then里的第一、二个参数分别加入到成功队列、失败队列
	then(success, fail) {
		this.done(success || function() {});
		this.fail(fail || function() {});
		return this;
	}
	// 程序出现异常时执行的函数
	catch(errFn) {
		if(typeof errFn !== "function") throw new Error("catch传入的参数必须为function");
		this.catchCb = errFn;
	}
	
}

代码解释:

Promise的核心是“发布-订阅”模式,因此需要一个doneList属性和一个failList属性,用来存储所有订阅者。

catchCb 属性用来存储产生异常时执行的回调函数。

done和fail负责将单个订阅放进doneList或failList。

catch负责放进异常时的回调函数。

then和done、fail一样,不同在于接受两个参数,分别放进doneList 和 failList。

resolve实现发布,此时遍历doneList,执行其中所有订阅者。

reject实现发布,此时遍历failList,执行其中所有订阅者。

constructor里为什么要使用setTimeout为0s?答:目的是将其里面的代码放入等待队列,待所有回调函数全部转入Promise容器时,才执行等待队列的代码。

下面进入测试:

new MyPromise((resolve, reject) => {
    setTimeout(() => {
        // noExistFn(); // 抛出异常,触发执行 ①
        // resolve("成功了!"); // 触发执行 ②
        reject("失败了!"); // 触发执行 ③
    }, 1000);
}).then((res) => {
    console.log("res >>> ", res) ①
}, (err) => {
    console.log("err >> ", err) ②
}).catch((exception) => {
    console.log("异常 >> ", exception); ③
});

结果如上,执行noExistFn时,会相应触发①,以此类推

 

你可能感兴趣的:(ES6,Promise,异步)