promise專題--手寫promise03

翻滾吧,小牛牛發表於2020-11-03

上篇回顧

promise專題–手寫promise02
上篇我們解決了非同步呼叫的問題,但是發現鏈式呼叫是行不通的。這篇解決這個問題。

一、問題分析

原生promise為什麼支援then的鏈式呼叫?因為原生每次then之後會返回一個promise物件,所以可以支援鏈式呼叫,但是上篇我們寫的並沒有返回一個promise物件,所以當我們再then的時候,就是undefined.then,所以理所當然直接報錯嘍,所以鏈式呼叫的核心就是要返回一個promise物件,下面看怎麼做!

二、重寫then方法

1、因為要返回一個promise物件,所以我們直接搭建新的程式碼框架,具體為

	Promise.prototype.then = function (onFulfilled, onRejected) {
		let newPromise = new Promise((resolve, reject) => {})
		return newPromise ;
	}

2、重寫上一篇的三種情況,因為每次返回一個promise,所以我們得知道上一個執行的到底是成功了還是失敗了,所以當拿到結果的時候我們需要一個方法來解析這個promise到底是成功了還是失敗了。

	Promise.prototype.then = function (onFulfilled, onRejected) {
		let newPromise = new Promise((resolve, reject) => {
			if (_this.status === "fulfilled") {
          	   setTimeout(() => {
                // 需要使用newPromise,所以需要放入非同步程式碼中
                try {
                    let res = onFulfilled(_this.successValue);
                    //resolve(res);
                    // 對res進行解析判斷
                    resolvePromise(promise2, res, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            }, 0)
        }
	})
		return newPromise ;
	}
	function resolvePromise(promise,res, resolve, reject) {
		// 這裡需要判斷一個迴圈引用的問題
		if (res === promise) {
	        return reject(new TypeError("迴圈引用!"));
	    }
	    // 判斷是否是一個物件或者函式
	    if (res != null && typeof res === 'object' || typeof res === 'function') {
	        // 判斷是否是promise
	        try {
	            let then = res.then; // then有可能丟擲異常
	            if (typeof then === 'function') {
	                // 將其認為是一個promise,然後執行then
	                then.call(res, (y) => {
	                    resolve(y);
	                }, (r) => {
	                    reject(r);
	                });
	            } else {
	                // 認為是一個普通的值
	                resolve(res);
	            }
	        }catch (e) {
	            reject(e);
	        }
	
	    } else {
	        // 非引用型別 也就是一個普通值
	        resolve(res);
	    }
}

3、失敗和非同步的重寫如下,整體程式碼如下:

	Promise.prototype.then = function (onFulfilled, onRejected) {
	    let _this = this;
	    // then被執行,需要再次返回一個新的promise例項
	    // 需要拿到當前then方法的結果也就是得知道成功或者失敗
	    let newPromise = new Promise((resolve, reject) => {
	        if (_this.status === "fulfilled") {
	            setTimeout(() => {
	                // 需要使用promise2,所以需要放入非同步程式碼中
	                try {
	                    let res = onFulfilled(_this.successValue);
	                    //resolve(res);
	                    // 對res進行解析判斷
	                    resolvePromise(newPromise, res, resolve, reject);
	                } catch (e) {
	                    reject(e);
	                }
	            }, 0)
	        }
	
	        if (_this.status === "rejected") {
	            setTimeout(() => {
	                try {
	                    let res = onRejected(_this.errReason);
	                    resolvePromise(newPromise, res, resolve, reject);
	                } catch (e) {
	                    reject(e);
	                }
	            }, 0)
	        }
	
	        if (_this.status === "pending") {
	            _this.onResolvedCallbacks.push(function () {
	                setTimeout(() => {
	                    try {
	                        let res = onFulfilled(_this.successValue);
	                        resolvePromise(newPromise, res, resolve, reject);
	                    } catch (e) {
	                        reject(e);
	                    }
	                }, 0)
	            })
	            _this.onRejectedCallbacks.push(function () {
	                setTimeout(() => {
	                    try {
	                        let res = onRejected(_this.errReason);
	                        resolvePromise(newPromise, res, resolve, reject);
	                    } catch (e) {
	                        reject(e);
	                    }
	                }, 0)
	
	            })
	        }
	    });
	    return newPromise;
}

三、大體思路

1.能夠鏈式呼叫,肯定then方法最後需要返回一個Promise例項;
2. 在then方法中用res去接收成功或者失敗的返回值,當成功或失敗方法丟擲錯誤,直接執行reject。因為要分析成功或者失敗的回撥,所以專門抽出一個方法resolvePromise用來分析返回值;
3. resolvePromise方法中傳入了四個引數,then中的newPromise,res值;
4. 如果res與promise相等,說明重複引用了,直接報錯幹掉;
5. 當res不是null,是個物件型別or函式型別,並且他的then方法也是函式型別時,就可以認為res他是個promise例項,執行x.then()方法;再用resolvePromise方法分析他的成功的返回值即可;
6. 如果res不是null不是object或function,就可以將其認為一個普通值,執行resolve方法即可;
7. 如果res.then方法丟擲異常了,直接呼叫reject方法就ok嘍;

四、支援then穿透

原生promise支援then穿透也就是

	p.then().then().then(()= > {....})

如何實現?
思路: then方法返回執行promise前,判斷下,如果是穿透的話,返回的不是一個function型別,處理下就ok

	Promise.prototype.then = function (onFulfilled, onRejected) {
	    // 穿透處理
	    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data;
	    onRejected = typeof onRejected === 'function' ? onRejected : reason => {
	        throw reason
	    }
	    .......
   }

下一篇實現all, race, resolve,reject,catch,finally方法

相關文章