国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

解析 Promise 原理,實(shí)現(xiàn)一個(gè)Promise

silenceboy / 1876人閱讀

摘要:解析原理,實(shí)現(xiàn)一個(gè)概述這篇文章旨在解析的異步實(shí)現(xiàn)原理,并且以中的為藍(lán)本實(shí)現(xiàn)一個(gè)簡(jiǎn)單的。具體的規(guī)范可以參見細(xì)節(jié)構(gòu)造器中必須傳入函數(shù),否則會(huì)拋出錯(cuò)誤。中的回調(diào)返回值會(huì)影響返回的對(duì)象。執(zhí)行器傳入構(gòu)造器的為函數(shù),并且在構(gòu)造時(shí)就會(huì)執(zhí)行。

解析 Promise 原理,實(shí)現(xiàn)一個(gè)Promise 概述

這篇文章旨在解析 Promise的異步實(shí)現(xiàn)原理,并且以 ES6中的 Promise 為藍(lán)本實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 Promise。

通過自己動(dòng)手實(shí)現(xiàn)一個(gè) Promise 對(duì)象,可以熟悉很多可能不知道的 Promise 細(xì)節(jié),同時(shí)也能對(duì)異步的理解更提升一步。

本文假設(shè)讀者對(duì) Promise 規(guī)范有一定理解,并且熟悉 ES6 中的 Promise 基本操作。

Promise 核心

Promise 概括來說是對(duì)異步的執(zhí)行結(jié)果的描述對(duì)象。(這句話的理解很重要)

Promise 規(guī)范中規(guī)定了,promise 的狀態(tài)只有3種:

pending

fulfilled

rejected

顧名思義,對(duì)上面3個(gè)狀態(tài)的解釋就不再贅述,Promise 的狀態(tài)一旦改變則不會(huì)再改變

Promise 規(guī)范中還規(guī)定了 Promise 中必須有 then 方法,這個(gè)方法也是實(shí)現(xiàn)異步的鏈?zhǔn)讲僮鞯幕尽?/p>

具體的規(guī)范可以參見:https://promisesaplus.com

ES6 Promise細(xì)節(jié)

Promise 構(gòu)造器中必須傳入函數(shù),否則會(huì)拋出錯(cuò)誤。(沒有執(zhí)行器還怎么做異步操作。。。)

Promise.prototype上的 catch(onrejected) 方法是 then(null,onrejected) 的別名,并且會(huì)處理鏈之前的任何的reject。

Promise.prototype 上的 then和 catch 方法總會(huì)返回一個(gè)全新的 Promise 對(duì)象

如果傳入構(gòu)造器的函數(shù)中拋出了錯(cuò)誤,該 promise 對(duì)象的[[PromiseStatus]]會(huì)賦值為 rejected,并且[[PromiseValue]]賦值為 Error 對(duì)象。

then 中的回調(diào)如果拋出錯(cuò)誤,返回的 promise 對(duì)象的[[PromiseStatus]]會(huì)賦值為 rejected,并且[[PromiseValue]]賦值為 Error 對(duì)象。

then 中的回調(diào)返回值會(huì)影響 then 返回的 promise 對(duì)象。(下文會(huì)具體分析)

這部分內(nèi)容參考: http://es6.ruanyifeng.com/#do...

動(dòng)手實(shí)現(xiàn)

做了上面的鋪墊,實(shí)現(xiàn)一個(gè) Promise 的思路就清晰很多了,本文使用 ES6 來進(jìn)行實(shí)現(xiàn),暫且把這個(gè)類取名為 GPromise吧(不覆蓋原生的,便于和原生進(jìn)行對(duì)比測(cè)試)。下文中 GPromise 代指將要實(shí)現(xiàn)的類,Promise 代指 ES6中的 Promise 類。

內(nèi)部屬性

在瀏覽器中打印出一個(gè) Promise 實(shí)例會(huì)發(fā)現(xiàn)其中會(huì)包括兩用"[[ ]]"包裹起來的屬性,這是系統(tǒng)內(nèi)部屬性,只有JS 引擎能夠訪問。

[[PromiseStatus]]
[[PromiseValue]]

以上兩個(gè)屬性分別是 Promise 對(duì)象的狀態(tài)和最終值。

我們自己不能實(shí)現(xiàn)內(nèi)部屬性,JS中私有屬性特性(#修飾符現(xiàn)在還是提案)暫時(shí)也沒有支持,所以暫且用"_"前綴規(guī)定私有屬性,這樣就模擬了Promise 中的兩個(gè)內(nèi)部屬性。

class GPromise {
        constructor(executor) {
            this._promiseStatus = GPromise.PENDING;
            this._promiseValue;
            this.execute(executor);
        }
        
        execute(executor){
            //...
        }
        
        then(onfulfilled, onrejected){
            //...
        }
    }

    GPromise.PENDING = "pedding";
    GPromise.FULFILLED = "resolved";
    GPromise.REJECTED = "rejected";
執(zhí)行器

傳入構(gòu)造器的executor為函數(shù),并且在構(gòu)造時(shí)就會(huì)執(zhí)行。

我們給 executor 中傳入 resolve 和 reject 參數(shù),這兩個(gè)參數(shù)都是函數(shù),用于改變改變 _promiseStatus和 _promiseValue 的值。

并且內(nèi)部做了捕獲異常的操作,一旦傳入的executor 函數(shù)執(zhí)行拋出錯(cuò)誤,GPromise 實(shí)例會(huì)變成 rejected狀態(tài),即 _promiseStatus賦值為"rejected",并且 _promiseValue賦值為Error對(duì)象。

  execute(executor) {
            if (typeof executor != "function") {
                throw new Error(` GPromise resolver ${executor} is not a function`);
            }
            //捕獲錯(cuò)誤
            try {
                executor(data => {
                    this.promiseStatus = GPromise.FULFILLED;
                    this.promiseValue = data;
                }, data => {
                    this.promiseStatus = GPromise.REJECTED;
                    this.promiseValue = data; 
                });
            } catch (e) {
                this.promiseStatus = GPromise.REJECTED;
                this.promiseValue = e;
            }
        }

注:Promise 對(duì)象在executor 發(fā)生錯(cuò)誤或者reject 時(shí),如果沒有then
或者 catch 來處理,會(huì)把錯(cuò)誤拋出到外部,也就是會(huì)報(bào)錯(cuò)。GPromise 實(shí)現(xiàn)的是沒有向外部拋出錯(cuò)誤,只能由then方法處理。

then方法
異步實(shí)現(xiàn)

then 方法內(nèi)部邏輯稍微復(fù)雜點(diǎn),并且有一點(diǎn)一定一定一定要注意到: then 方法中的回調(diào)是異步執(zhí)行的,思考下下段代碼:

console.log(1);
new Promise((resolve,reject)=>{
    console.log(2);
    resolve();
})
.then(()=>console.log(3));
console.log(4);

執(zhí)行結(jié)果是什么呢?答案其實(shí)是:1 2 4 3。傳入Promise 中的執(zhí)行函數(shù)是立即執(zhí)行完的啊,為什么不是立即執(zhí)行 then 中的回調(diào)呢?因?yàn)閠hen 中的回調(diào)是異步執(zhí)行,表示該回調(diào)是插入事件隊(duì)列末尾,在當(dāng)前的同步任務(wù)結(jié)束之后,下次事件循環(huán)開始時(shí)執(zhí)行隊(duì)列中的任務(wù)。

then 方法中的難點(diǎn)就是處理異步,其中一個(gè)方案是通過 setInterval來監(jiān)聽GPromise 對(duì)象的狀態(tài)改變,一旦改變則執(zhí)行相應(yīng)then 中相應(yīng)的回調(diào)函數(shù)(onfulfilled和onrejected),這樣回調(diào)函數(shù)就能夠插入事件隊(duì)列末尾,異步執(zhí)行,實(shí)驗(yàn)證明可行,這種方案是最直觀也最容易理解的。

then 返回值

then 方法的返回值是一個(gè)新的 GPromise 對(duì)象,并且這個(gè)對(duì)象的狀態(tài)和 then 中的回調(diào)返回值相關(guān),回調(diào)指代傳入的 onfulfilled 和 rejected。

如果 then 中的回調(diào)拋出了錯(cuò)誤,返回的 GPromise 的 _promiseStatus 賦值為"rejected", _promiseValue賦值為拋出的錯(cuò)誤對(duì)象。

如果回調(diào)返回了一個(gè)非 GPromise 對(duì)象, then返回的 GPromise 的 _promiseStatus 賦值為"resolved", _promiseValue賦值為回調(diào)的返回值。

如果回調(diào)返回了一個(gè) GPromise 對(duì)象,then返回的GPromise對(duì)象 的_promiseStatus和 _promiseValue 和其保持同步。也就是 then 返回的GPromise記錄了回調(diào)返回的狀態(tài)和值,不是直接返回回調(diào)的返回值。

代碼

then 方法中的重點(diǎn)邏輯如上,其他參見代碼即可:

  then(onfulfilled, onrejected) {
            let _ref = null,
                timer = null,
                result = new GPromise(() => {});

            //因?yàn)?promise 的 executor 是異步操作,需要監(jiān)聽 promise 對(duì)象狀態(tài)變化,并且不能阻塞線程
            timer = setInterval(() => {
                if ((typeof onfulfilled == "function" && this._promiseStatus == GPromise.FULFILLED) ||
                    (typeof onrejected == "function" && this._promiseStatus == GPromise.REJECTED)) {
                    //狀態(tài)發(fā)生變化,取消監(jiān)聽
                    clearInterval(timer);
                    //捕獲傳入 then 中的回調(diào)的錯(cuò)誤,交給 then 返回的 promise 處理
                    try {
                        if (this._promiseStatus == GPromise.FULFILLED) {
                            _ref = onfulfilled(this._promiseValue);
                        } else {
                            _ref = onrejected(this._promiseValue);
                        }

                        //根據(jù)回調(diào)的返回值來決定 then 返回的 GPromise 實(shí)例的狀態(tài)
                        if (_ref instanceof GPromise) {
                            //如果回調(diào)函數(shù)中返回的是 GPromise 實(shí)例,那么需要監(jiān)聽其狀態(tài)變化,返回新實(shí)例的狀態(tài)是根據(jù)其變化相應(yīng)的
                            timer = setInterval(()=>{
                                if (_ref._promiseStatus == GPromise.FULFILLED ||
                                    _ref._promiseStatus == GPromise.REJECTED) {
                                    clearInterval(timer);
                                    result._promiseValue = _ref._promiseValue;
                                    result._promiseStatus = _ref._promiseStatus;
                                }
                            },0);
                            
                        } else {
                            //如果返回的是非 GPromise 實(shí)例
                            result._promiseValue = _ref;
                            result._promiseStatus = GPromise.FULFILLED;
                        }
                    } catch (e) {
                        //回調(diào)中拋出錯(cuò)誤的情況
                        result._promiseStatus = GPromise.REJECTED;
                        result._promiseValue = e;
                    }
                }
            }, 0);
            //promise 之所以能夠鏈?zhǔn)讲僮鳎驗(yàn)榉祷亓薌Promise對(duì)象
            return result;
        }
測(cè)試用例

是騾子是馬,拉出來溜溜。。

測(cè)試環(huán)境是macOS Sierra 10.12.6,Chrome 60.0.3112.113。

經(jīng)過以下測(cè)試, 證明了GPromise 的基本的異步流程管理和原生 Promise 沒有差別。以下測(cè)試用例參考了 MDN 中的[Promise
API](https://developer.mozilla.org... 中的 Advanced Example。

    var promiseCount = 0;

    function test(isPromise) {
        let thisPromiseCount = ++promiseCount,
            executor = (resolve, reject) => {
                console.log(thisPromiseCount + ") Promise started (Async code started)");
                window.setTimeout(
                    function () {
                        resolve(thisPromiseCount);
                    }, Math.random() * 2000 + 1000);
            };

        console.log(thisPromiseCount + ") Started (Sync code started)");

        let p1 = isPromise ? new Promise(executor) : new GPromise(executor);

        p1.then(
            function (val) {
                console.log(val + ") Promise fulfilled (Async code terminated)");
            },
            function (reason) {
                console.log("Handle rejected promise (" + reason + ") here.");
            });

        console.log(thisPromiseCount + ") Promise made (Sync code terminated)");
    }

    test();
    test(true);
    test();

那么再來測(cè)試下鏈?zhǔn)讲僮鳎]有鏈?zhǔn)讲僮鞯?Promise 我要你有何用?),測(cè)試結(jié)果和 Promise 表現(xiàn)一致。

    function async1() {
        return new GPromise(
            (resolve, reject) => {
                console.log("async1 start");
                setTimeout(() => {
                    resolve("async1 finished")
                }, 1000);
            }
        );
    }

    function async2() {
        return new GPromise(
            (resolve, reject) => {
                console.log("async2 start");
                setTimeout(() => {
                    resolve("async2 finished")
                }, 1000);
            }
        );
    }

    function async3() {
        return new GPromise(
            (resolve, reject) => {
                console.log("async3 start");
                setTimeout(() => {
                    resolve("async3 finished");
                }, 1000);
            }
        );
    }

    async1()
        .then(
            data => {
                console.log(data);
                return async2();
            })
        .then(
            data => {
                console.log(data);
                return async3();
            }
        )
        .then(
            data => {
                console.log(data);
            }
        );
總結(jié)

到此為止,一個(gè)高仿的 Promise 已經(jīng)實(shí)現(xiàn)完成了,它很簡(jiǎn)單,因?yàn)橹挥幸粋€(gè) then 方法,異步的狀態(tài)管理由內(nèi)部完成。

這里并沒有實(shí)現(xiàn) catch方法,因?yàn)樯衔囊蔡岬搅耍琧atch方法就相當(dāng)于 then(null,onrejected) 。而且 Promise 類上的 race,all,resolve,reject也沒有實(shí)現(xiàn),本文旨在理清 Promise 核心原理,篇幅受限(其實(shí)就是我懶),其他輔助類的方法等之后有時(shí)間再實(shí)現(xiàn)。

本文提供的只是一個(gè)思路,希望能幫助到你,歡迎大家批評(píng)指教。

代碼地址:Github

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/91948.html

相關(guān)文章

  • Promise原理分析二

    摘要:原理分析一說明方法返回一個(gè)被拒絕的對(duì)象。實(shí)現(xiàn)創(chuàng)建一個(gè)新的對(duì)象,通過其構(gòu)造函數(shù)的參數(shù)函數(shù)對(duì)象將狀態(tài)變?yōu)椤:褪褂媒馕鲋担瑫r(shí)通過構(gòu)造函數(shù)的參數(shù)的函數(shù)對(duì)象觸發(fā)的狀態(tài)轉(zhuǎn)變,其中使用數(shù)組記錄返回值使用索引值以確保其返回值在結(jié)果集中的順序。 Promise原理分析二 前面我們分析了Promise的then和catch方法,接下來我們一起來看看reject、resolve、race和all方法的實(shí)現(xiàn)...

    OnlyMyRailgun 評(píng)論0 收藏0
  • 【Step-By-Step】高頻面試題深入解析 / 周刊05

    摘要:關(guān)于點(diǎn)擊進(jìn)入項(xiàng)目是我于開始的一個(gè)項(xiàng)目,每個(gè)工作日發(fā)布一道面試題。那個(gè)率先改變的實(shí)例的返回值,就傳遞給的回調(diào)函數(shù)。通過插入標(biāo)簽的方式來實(shí)現(xiàn)跨域,參數(shù)只能通過傳入,僅能支持請(qǐng)求。因此清除浮動(dòng),只需要觸發(fā)一個(gè)即可。 關(guān)于【Step-By-Step】 Step-By-Step (點(diǎn)擊進(jìn)入項(xiàng)目) 是我于 2019-05-20 開始的一個(gè)項(xiàng)目,每個(gè)工作日發(fā)布一道面試題。每個(gè)周末我會(huì)仔細(xì)閱讀大家的...

    xiangchaobin 評(píng)論0 收藏0
  • JavaScript 工作原理之四-事件循環(huán)及異步編程的出現(xiàn)和 5 種更好的 async/await

    摘要:函數(shù)會(huì)在之后的某個(gè)時(shí)刻觸發(fā)事件定時(shí)器。事件循環(huán)中的這樣一次遍歷被稱為一個(gè)。執(zhí)行完畢并出棧。當(dāng)定時(shí)器過期,宿主環(huán)境會(huì)把回調(diào)函數(shù)添加至事件循環(huán)隊(duì)列中,然后,在未來的某個(gè)取出并執(zhí)行該事件。 原文請(qǐng)查閱這里,略有改動(dòng)。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第四章。 現(xiàn)在,我們將會(huì)通過回顧單線程環(huán)境下編程的弊端及如何克服這些困難以創(chuàng)建令人驚嘆...

    maochunguang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<