91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

理解異步之美:Promise 與 async await(二)

發布時間:2020-07-08 08:32:43 來源:網絡 閱讀:1894 作者:MDove 欄目:web開發

承上啟下

理解異步之美:Promise與async await(一)

經歷了上一篇基礎的Promise講解后我覺得大家對于promise的基本用法和想法就有一定了解了。(就是一種承諾喲)

下面我們要去了解一下它的工作流程。

結合源碼與分析別人的常見實現進行理解

下面是別人實現的總源碼,(簡單一看就可以)

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise(callback) {
    this.status = PENDING;
    this.value = null;
    this.defferd = [];
    setTimeout(callback.bind(this, this.resolve.bind(this), this.reject.bind(this)), 0);
}
    Promise.prototype = {
        constructor: Promise,
        resolve: function (result) {
            this.status = FULFILLED;
            this.value = result;
            this.done();
        },
        reject: function (error) {
            this.status = REJECTED;
            this.value = error;
        },
        handle: function (fn) {
            if (!fn) {
                return;
            }
            var value = this.value;
            var t = this.status;
            var p;
            if (t == PENDING) {
                this.defferd.push(fn);
            } else {
                if (t == FULFILLED && typeof fn.onfulfiled == 'function') {
                    p = fn.onfulfiled(value);
                }
                if (t == REJECTED && typeof fn.onrejected == 'function') {
                    p = fn.onrejected(value);
                }
                var promise = fn.promise;
                if (promise) {
                    if (p && p.constructor == Promise) {
                        p.defferd = promise.defferd;
                    } else {
                        p = this;
                        p.defferd = promise.defferd;
                        this.done();
                    }
                }
            }
        },
        done: function () {
            var status = this.status;
            if (status == PENDING) {
                return;
            }
            var defferd = this.defferd;
            for (var i = 0; i < defferd.length; i++) {
                this.handle(defferd[i]);
            }
        },
        then: function (success, fail) {
            var o = {
                onfulfiled: success,
                onrejected: fail
            };
        var status = this.status;
        o.promise = new this.constructor(function () {});
        if (status == PENDING) {
            this.defferd.push(o);
        } else if (status == FULFILLED || status == REJECTED) {
            this.handle(o);
        }
        return o.promise;
        }
    };

這是網上一份常見的Promise的源碼實現我會對這個進行一個分析
(肯定有人問為什么不自己實現一個? 解:省時、網上太多了、本質還是要了解思想)

話不多說開始咯

咱們先大體梳理一下實現的東西要能干什么?

first :

let promsie = new Promise((resolve,reject)=>{
    doSomething()
})
根據這個構造函數,我們需要實現兩個方法,resolve、reject方法。

second :

promise.then(res=>{
    doSomethingRes();
},rej=>{
    doSomenthingRej()
})
我們要實現一個then方法,可以去根據不同狀態來執行不同的函數。

最基本的兩個內容我們已經確定了。

話不多說開始分析代碼。

對代碼的分析在內容的注釋上大家不要遺漏哈!!!

第一段構造函數與狀態設定

// 首先聲明三個狀態,
// 狀態的就是上一節說的:事情是進行中、已完成、失敗了。
// 這三種狀態遵循著PENDING->FULEFILLED 或者PENDING->REJECTED
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
// Promise構造函數接收u一個回調函數
function Promise(callback) {
    // 新new出來的實例的status一定是PENDING.
    this.status = PENDING;
    // value是指當你事情完成、失敗后內部保存的值
    // 用法是resolve(42) 在then函數的res=>{dosomething()res就是42
    }
    this.value = null;
    // defferd 字面意思推遲、是個數組,存放這個promise以后要執行的事件
    // 類比發布訂閱模式(觀察者模式)。存放觀察者在被觀察者身上訂閱的事件列表
    // defferd內的事件存放著日后觀察者要執行的事件。
    this.defferd = [];
    // setTimeout異步的去執行new 一個promise實例內執行的任務,不去阻塞主線程。
    //這一段代碼我有一點疑惑,new promise實例時,callback的執行并不是異步的。
    // 而這里選擇異步的并不是很合理。
    // bind函數的作用。callback的參數如何指定?通過bind方法將函數函數柯里化(Currying 和一個NBA球星的名字一樣很好記)
    // 而且綁定函數的this執行。函數內的this都執行這個new 出來的promise實例
    // 去指定函數執行時的參數,將resolve方法與reject方法強制做為callback的參數。
    // 所以我們寫的回調函數,參數怎么命名都可以執行到對應的resolve與reject方法
    setTimeout(callback.bind(this, this.resolve.bind(this), this.reject.bind(this)), 0);
}

自己實現與官方Promise執行的對比。大家可以看一下這個setTimeout導致的執行順序問題。所以閱讀別人對各種功能實現時要學會對照的去看。
理解異步之美:Promise 與 async await(二)cdn.xitu.io/2018/8/18/1654c206c85e9099?w=1124&h=440&f=png&s=88739">

理解異步之美:Promise 與 async await(二)

到這里伙伴們已經了解了我們new 一個構造函數時都會做哪些事情。

1:對promise實例定義一個狀態,值為PENDING。

2:給promise實例定義一個存放值的空間。

3:設置一個發布列表,在以后的指定時間發布其中的事件。

4:通過bind函數將callback柯里化,使callback執行時調用對應的resolve與reject方法,并執行callback

第二段 resolve reject then方法的分析

為什么先說這三個方法。
因為resolve、reject是核心方法,不說都不行,可是resolve與reject完成要做的事情必須是then方法指定的所以三個方法之間關系密切。

// 在Promise的原型對象上指定這些方法。
// 這種做法有很大弊端、并且Promise源碼也并不是這么做的之后會進行分析
Promise.prototype = {
        // 覆蓋式的指定Promise的原型對象會導致constructor屬性丟失
        // 在這里進行填補,手動指定Promise原型對象上的constructor屬性
        constructor: Promise,
        // resolve方法開始 接收一個結果(可以為空)
        resolve: function (result) {
            //更改狀態為FULFILLED。
            this.status = FULFILLED;
            // 將result存放在之前構造函數中提到的存放結果的空間中
            this.value = result;
            // done方法。表示執行完畢(后面會繼續將)
            this.done();
        },
        // 與resolve方法類似 不多做解釋
        reject: function (error) {
            // 狀態更改
            this.status = REJECTED;
            this.value = error;
            // 沒有done函數,這塊做法很有問題下面會配圖解釋。
        },
        // then方法開始要好好講講
        // success表示狀態變成FULFILLED時要執行的函數
        // fail表示狀態變成REJECTED時要執行的函數
        then: function (success, fail) {
        // 聲明一個對象來存放這些事件。
            var o = {
                onfulfiled: success,
                onrejected: fail
            };
        // 獲取當前promise的狀態。
        // 這個的意義是,我們對promise實例執行then方法的時候有兩種情況
        // 一:promise實例的內容還沒有執行完畢。二:promise實例內容已經執行完畢并且狀態已經改變。繼續下面。
        var status = this.status;
        o.promise = new this.constructor(function () {});
        // 如果狀態是PENDING,表示實例內容還未執行完畢。
        // 說明then方法指定在某種狀態要執行的事件是未來發生的現在并不執行。
        // 所以將o放入defferd訂閱列表中。
        // 這個之前講過defferd中的內容會在某個條件觸發后會執行。
        // 所以當promise實例內容還未完成就要把未來執行的方法放入訂閱列表
        if (status == PENDING) {
            this.defferd.push(o);
        // 對應之前說的情況二    
        // 狀態變成以下兩種情況怎么辦?
        // 訂閱列表內不應該有當前情況的o。
        // 所以要立即執行當前指定的事件,而且未來的任何情況下這次指定的事件也不會執行。
        //所以不會放入defferd中
        } else if (status == FULFILLED || status == REJECTED) {
           // 執行handle函數
            this.handle(o);
        }
        // then方法存在鏈式調用,then方法的返回值必須是一個promise對象
        return o.promise;
        }
    };

到這里我們大體梳理清楚,resolve、reject、then方法的用處。

提一嘴 reject方法沒有執行done函數會導致以下情況

理解異步之美:Promise 與 async await(二)

一:在new promise實例過程中執行的callback函數,在函數執行的過程中肯定會調用resolve或者reject(兩個都調用也可能)。當調用了resolve方法之后會改變promise的狀態,存放結果。表示任務完成,執行done函數。(reject就不再來一遍了)

二:then方法的執行事件與resolve方法沒有任何先后順序可言。隨心所欲誰在前面都不一定。在resolve(reject)之前執行,就注冊一下要執行的事件。在resolve(reject)之后執行就直接執行就可以了,并且不要注冊。

第三段 具體是怎么執行的呢?聊聊done與handle

同學們按照代碼執行的順序,我們應該先去看done方法。然后再看handle所以辛苦一下,先向下一點找到可愛的done方法。

// 看完done方法的朋友肯定對我這種方式很鬧心,保證你們看的熱情嘛。哈哈哈哈哈
// 沒看done方法的快回去看、快回去看。
// 必須提一下 下面一直說的o是什么? o是在then方法中傳入defferd數組中的對象,一下簡稱為o。
// handle是干嘛的??? 那是用來執行o的。o里面放著我們想要執行的內容
// 大家再回憶以下,handle還在哪里執行了?想起來了吧,當then方法執行時
// 如果狀態已經改變了。那么就直接handle(o),執行你要做的事情。
handle: function (fn) {
    // o不存在的???媽耶,咋辦呀。那就是defferd中沒東西。好吧什么都不做
    if (!fn) {
        return;
    }
    var value = this.value;
    var t = this.status;
    var p;
    // 如果狀態為PENDING,表示還沒到o要執行的內容。那么不能執行的?
    if (t == PENDING) {

        this.defferd.push(fn);
    } else {
        // 這里面很容易看的,狀態變成FULFILLED,
        //并且你在給狀態是FULFILLED時要做的事情可以執行(函數才能執行呀,你寫個字符串不報錯了??)
        // 執行咯。這里面大家一看就知道,你then方法里面res=>{doSometthing(res)}
        //這個res就是promise內存放的結果(value)。
        if (t == FULFILLED && typeof fn.onfulfiled == 'function') {
            p = fn.onfulfiled(value);
        }
        // 不多提了。
        if (t == REJECTED && typeof fn.onrejected == 'function') {
            p = fn.onrejected(value);
        }
        // 但是這個p是干什么的????
        // 存放方法的返回值,為了鏈式調用。實現鏈式調用的是什么方法?
        // 返回的o.promise. 那么返回的o.promise不存在呢?(當然這是不可能的)
        // 那就沒有鏈式調用。
        // promise中有一個方法,當then函數內的事件(指的這個函數:res=>{})
        // 返回值是一個promise對象時,那么then的返回值就是這個promise對象
        // 鏈式中的下一個then就會等待這個promise執行完畢。
        // 如果不是promise對象怎么辦?那么就執行鏈條后面的then方法注冊的事情。
        var promise = fn.promise;
        if (promise) {
            // 如果你注冊的事件執行后的返回值是一個promise對象
            if (p && p.constructor == Promise) {
                // 當前這個p(是個promise對象)可以把o.promise對象訂閱列表內的事件拿過來。
                // 串行后,返回的promise繼續控制著defferd的內容。
                //理論上講,按剛才的邏輯來寫,每個promise對象內的defferd,都應該只有一個值。
                // 因為串行的鏈條每個then注冊的事件都在上一個then返回的o.promise的defferd內。
                // 那么為什么?defferd要寫個數組呢???這是我疑惑的地方但是影響不大
                p.defferd = promise.defferd;
            } else {
               // 如果不是promise呢?那么就把當前的promise對象當作你的返回值
               // 繼續繼承o.promise里面的defferd
                p = this;
                p.defferd = promise.defferd;
                // 并沒有任何承諾,p應該就是一個resolved(reject)狀態
                // 直接執行done方法就可以啦。
                this.done();
            }
        }
    }
},
// done方法是在resolve方法(reject為啥沒寫之前有講過)中執行的,表示resolve方法執行完畢了。
// 這個完畢是一種明確信號,那就是之前說好的狀態變成FULFILLED我要做的那些事情。
// 鄉親們、弟兄們咱們可以被執行了
done: function () {
    // 當然為了保險起見PENDING狀態肯定不會執行,return掉。
    // done函數在PENDING狀態也不會被調用呀。雙重保險嘛
    var status = this.status;
    if (status == PENDING) {
        return;
    }
    // 鄉親們、兄弟們在哪呢?就在你的defferd中。我們的訂閱列表內的兄弟們該執行了。
    // 遍歷以下我們的defferd對象,誰也別漏下都給我執行了。
    var defferd = this.defferd;
    for (var i = 0; i < defferd.length; i++) {
    // 問題來了鄉親們不是函數是一個對象啊。
    //為啥是對象?在then方法中有defferd.push(o);o是啥?是個對象啊。
    // 那咋執行????需要一個特定來執行o的方法,就是handle。
    // 好了伙伴們可以把文章回到上面一點了。
        this.handle(defferd[i]);
    }
},

這一段我已經把handle與done方法說完了。主要是為了鏈式調用。才會設計的這樣子。所以鏈式調用還是很搶手的一個功能。
自己也可以嘗試的去實現一下符合promise規范的promise功能。

親! 學習完要思考

不知道看到這里大家對網上常見的promise源碼實現有一種什么樣的感覺???

我先說說我的感覺

看過源碼(抱歉我的智商是在有限,短時間內是真的看不懂啊),覺得源碼做的要合理太多了。看不懂我都覺得合理。。。。不是對強者的過分崇拜,而是真的很合理。網上常見的實現,只是單單的實現了功能,這樣的promise只適合有一定promise經驗并且守規矩的人使用。為什么這么說???

一:這樣實現的promise,狀態可以隨時人為的更改,對外暴露,沒有設置為私有屬性。

二:為了方便,選擇把方法設置在原型鏈上,導致無法使用私用變量。

三:reject的執行不足,只是對resolve進行合理的使用。

雖然我這么說,我也實現不出來,寫出這些的人還是比我厲害很多

promise的源碼則是(某個版本的,版本號我不記得了)

把resolve、reject、all、race,handle方法,都放在構造函數內。

把catch、then、chain方法放在原型上。

理解異步之美:Promise 與 async await(二)
有圖為證,字面意思應該是這個意思,我覺得我沒想錯。
在改變promise的狀態也好、value也好。都在頻繁的使用PromiseSet方法來設置屬性,對方法進行封裝,并且方便狀態的管理,附加合理的容錯。

理解異步之美:Promise 與 async await(二)

對比源碼之后,覺得自己雖然流程大體了解,但是這種精密而且優雅的方式,是短時間內很難去掌握的。promise的源碼當然會堅持看下去,網上能把promise按照規范實現一遍的人已經很厲害了。我雖然覺得還有地方可以修改,但是我比他們還差的遠(這種感覺就有點像:我不上,我就比比),要向他們學習,照這他們去努力。

別說了 喝雞湯吧

前端的學習之路還很漫長,我看過的(僅僅是看過的)源碼半只手就都數的過來。還是堅信堅持下去,自己就變得很棒。每個人都是從控制流語句學過來的,邏輯也不過是復雜的控制流程(還涉及高端的算法與設計模式),堅信自己一定可以成功!!!一起努力吧 每一個前端er(boy and girl)。所以一切源碼層面看不懂、不理解都可以歸結為看得少、想得少、理解的少。(和你的智商沒有任何關系喲)

下期預告

下一篇就是理解異步之美的終點篇了。異步的美好在于這種神奇的思想。抓住思想的尾巴,不被技術束縛,嘿嘿嘿。

要開新課題了。課題應該是圍繞著vue-router的源碼進行學習。一個與大家分享學習過程的周期性文章。盡情期待!!!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

平顺县| 舒城县| 金坛市| 隆化县| 本溪市| 嘉兴市| 永和县| 汽车| 汤原县| 七台河市| 高阳县| 阳春市| 涡阳县| 吉隆县| 婺源县| 兴义市| 榆中县| 新巴尔虎右旗| 阿瓦提县| 京山县| 揭阳市| 都匀市| 斗六市| 邹平县| 安徽省| 昔阳县| 高密市| 陆河县| 茂名市| 吉水县| 尚志市| 江华| 曲阜市| 来安县| 稷山县| 梓潼县| 开化县| 巴青县| 浦江县| 威信县| 吴江市|