手動實現Promise


  Promise對大家來說並不是很陌生,它是一個異步編程的解決方案,主要解決了前端回調地域問題。用阮老師的話說,它“就是一個容器,里面保存着某個未來才會結束的事件(通常是一個異步操作)的結果”。

  Promise有三種狀態:pending(初始狀態)、fulfilled(成功)、reject(失敗),初始狀態pending只能變成fulfilled或者reject,這一過程是不可逆的,當狀態發生改變時,會觸發對應的回調方法。除此之外,也支持鏈式調用,then/catch會返回一個Promise,以供鏈式調用,盜用MDN上的一張圖,Promise的執行流程如下圖所示:

  

  具體實現簡單分為以下四步:

    1、定義一個執行器fn,自帶兩個參數的函數,resolve/reject,在實例化Promise時,調用執行器fn,傳入參數reslove/reject,初始化回調事件隊列taskList
    2、在執行then方法時,判斷是不是初始狀態pending,如果是,則將then中fullfilled/reject的回調推進執行隊列taskList中,then方法返回一個promise實例
    3、實現鏈式回調中,用id來標識不同的promise實例
    4、當觸發了執行器中參數函數時,根據id來判斷當前執行的回調方法

  實現代碼:

 1  //公共變量,用於標識MyPromise實例
 2         index = 0;
 3         //promise接收一個回調函數fn,有兩個參數,reslove,reject
 4         function MyPromise(fn) {
 5             var _this = this;
 6             //promise的三種狀態
 7             this.RESOLVE = "fullfilled";
 8             this.PENDING = "pending";
 9             this.REJECT = "reject";
10             this.id = index++;
11             //初始默認狀態為penddding
12             this.state = this.PENDING;
13             //執行任務列表
14             this.taskList = [];
15             //最終執行的回調
16             this.finallyCallback = null;
17             //bind改變reslove/reject函數體內this的指向,確保指向MyPromise
18             fn.call(this, this.resolve.bind(this), this.reject.bind(this));
19         }
20 
21         MyPromise.prototype.resolve = function(value) {
22             this.state = this.RESOLVE;
23             //2、狀態變更時,執行完成的方法
24             this.taskList[this.id] && this.handler(this.taskList[this.id], value);
25         };
26 
27         MyPromise.prototype.reject = function(value) {
28             this.state = this.REJECT;
29             //2、狀態變更時,執行完成的方法
30             this.taskList[this.id] && this.handler(this.taskList[this.id], value);
31         };
32         //執行任務回調
33         MyPromise.prototype.handler = function(task, value) {
34             var result = null;
35             if (this.state === this.RESOLVE) {
36                 result = task.onFullFilled(value);
37             } else if (this.state === this.REJECT) {
38                 result = task.onReject(value);
39             }
40             var nextId = this.id + 1;
41             //需要判斷返回值是不是MyPromise實例,如果是,將之前的任務隊列賦值給新的MyPromise實例
42             if (result instanceof MyPromise) {
43                 result.id = nextId;
44                 result.taskList = this.taskList;
45                 result.finallyCallback = this.finallyCallback;
46             } else {
47                 //沒有返回MyPromise實例
48                 //如果有finally回調,則執行最終的回調
49                 this.finallyCallback && this.finallyCallback();
50             }
51         };
52         //onFullFilled:成功的回調,onReject:失敗的回調
53         MyPromise.prototype.then = function(onFullFilled, onReject) {
54             var _this = this,
55                 obj = {
56                     onFullFilled: onFullFilled,
57                     onReject: onReject
58                 };
59             //1、初始化時,將后續可能要執行的任務推送到執行任務隊列中
60             if (this.state === this.PENDING) {
61                 this.taskList.push(obj);
62             }
63             //返回一個promise,支持鏈式調用
64             return this;
65         };
66 
67         //最終執行的方法,不管MyPromise的狀態如何
68         MyPromise.prototype.finally = function(callback) {
69             this.finallyCallback = callback;
70         };

  測試代碼:

 var cc = new MyPromise(function(reslove, reject) {
            setTimeout(function() {
                reslove(2);
            }, 500);
        });
        var dd = new MyPromise(function(reslove, reject) {
            setTimeout(function() {
                reject(3);
            }, 500);
        });
        cc.then(function(num) {
                console.log(num);
                return dd;
            })
            .then(
                function(cc) {
                    console.log(cc);
                },
                function(e) {
                    console.log(5);
                }
            )
            .finally(function() {
                console.log("Game Over");
            });
        console.log(1);

  執行結果:

  

   實現過程簡單粗暴,如有問題,煩請指出,謝謝!

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM