天天看點

手撕代碼之手寫Promise

<!DOCTYPE html>
<html>
<head>
	<title>手寫Promise</title>
</head>
<body>

</body>
<script type="text/javascript">
	class MyPromise{
		constructor(executor){
			this.status = "pending";//目前狀态
			this.res = null;//傳遞給then的值
			this.err = null;//傳遞給錯誤處理的值
			this.resolveCallbacks = [];//resolve執行後的回調函數
			this.rejectCallbacks = [];//reject執行後的回調函數
			try{
				executor(this.resolve.bind(this),this.reject.bind(this));//執行器,傳入類中的resolve和reject方法,必須要用bind将this指向new出來的class,否則this指向目前上下文(執行器)就找不到this.resolve。
			}catch(error){
				this.reject(error);//如果執行器内部出錯,應該直接reject
			}

		}
		resolve(res){
			if(this.status !== "pending") return;//根據Promise的規則,已處理的Promise是不能改變狀态的
			this.status = "fulfilled";
			this.res = res;
			setTimeout(() => {//把then變成異步任務
				this.resolveCallbacks.map(
					(callbackFunction) => {
						callbackFunction.onFulfilled(res);
					}
					);
			})
		}
		reject(err){
			if(this.status !== "pending") return;
			this.status = "rejected";
			this.err = err;
			setTimeout(() => {
				this.rejectCallbacks.map(
					(callbackFunction) => {
						callbackFunction.onRejected(err);
					});
			})
		}
		then(onFulfilled,onRejected){
			//if判斷目前狀态,根據Promise的規則,必須被處理後才能執行then或者catch
			if(typeof onFulfilled !== "function"){
				onFulfilled = () => this.res;
			}
			if(typeof onRejected !== "function"){
				onRejected = () => this.err;//如果.then中沒有傳入處理錯誤的函數,就要處理一下避免報錯,傳遞this.res和this.err是為了then的穿透傳遞
			}
			return new MyPromise((resolve,reject) => {//.then傳回的是一個Promise,這樣才能鍊式調用
				if(this.status === "pending"){//如果執行到then了還是pending,說明執行器裡的是異步任務,就得将.then裡的函數傳遞到resolve或reject去讓它們異步執行。
					this.resolveCallbacks.push({
						onFulfilled: res => {
							this.parse(onFulfilled(res),resolve,reject);
						}
					}
					);
					this.rejectCallbacks.push({
						onRejected: err => {
							this.parse(onRejected(this.res),resolve,reject);
						}
					});
				}
				if (this.status === "fulfilled") {
					setTimeout(() => {//用setTimeout把then變成異步任務
						this.parse(onFulfilled(this.res),resolve,reject);
					})
				}
				if (this.status === "rejected") {
					setTimeout(() => {
						this.parse(onRejected(this.res),resolve,reject);
					})
				}
			})
		}
		parse(result,resolve,reject){//傳入的result是上一個Promise的傳回值
			try{
				resolve(result);//将then傳回的值傳遞到下一個Promise中以供鍊式調用
			}catch(error){
				rejected(error);//如果then的處理方法中出錯,傳回的Promise就應該為rejected
			}
		}
	}

	let p = new MyPromise((resolve,reject) => {
		setTimeout(() => {
			resolve("resolve了");
			// reject("reject了");
		},1000);
	}).then(
	res => {
		return res
	}
	).then(
	res => {
		console.log("第二層",res);
	}
	)
</script>
</html>
           

繼續閱讀