成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

從Google V8引擎剖析Promise實(shí)現(xiàn)

plokmju88 / 482人閱讀

摘要:從引擎剖析實(shí)現(xiàn)本文閱讀的源碼為,此版本的實(shí)現(xiàn)為版本,在后續(xù)版本繼續(xù)對(duì)其實(shí)現(xiàn)進(jìn)行了處理。引入了語(yǔ)法等,在版本迭代后,逐漸迭代成了版本實(shí)現(xiàn)。方法的調(diào)用暴露給外部的高版本為方法,如果當(dāng)前的指向的構(gòu)造函數(shù),則設(shè)置當(dāng)前的狀態(tài),否則調(diào)用函數(shù)執(zhí)行。

從Google V8引擎剖析Promise實(shí)現(xiàn)
?    本文閱讀的源碼為Google V8 Engine v3.29.45,此版本的promise實(shí)現(xiàn)為js版本,在后續(xù)版本Google繼續(xù)對(duì)其實(shí)現(xiàn)進(jìn)行了處理。引入了es6語(yǔ)法等,在7.X版本迭代后,逐漸迭代成了C版本實(shí)現(xiàn)。

? 貼上源碼地址:https://chromium.googlesource... 大家自覺(jué)傳送。

? 代碼中所有類似%functionName的函數(shù)均是C語(yǔ)言實(shí)現(xiàn)的運(yùn)行時(shí)函數(shù)。

Define variables

首先定義了將要在JS作用域使用了一些變量,提高了編譯器的效率。

var IsPromise;
var PromiseCreate;
var PromiseResolve;
var PromiseReject;
var PromiseChain;
var PromiseCatch;
var PromiseThen;
var PromiseHasRejectHandler;

隨后定義了一些全局私有變量供給和C語(yǔ)音交互,用于維護(hù)Promise的狀態(tài)和進(jìn)行Debug。

var promiseStatus = GLOBAL_PRIVATE("Promise#status");
var promiseValue = GLOBAL_PRIVATE("Promise#value");
var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve");
var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject");
var promiseRaw = GLOBAL_PRIVATE("Promise#raw");
var promiseDebug = GLOBAL_PRIVATE("Promise#debug");
var lastMicrotaskId = 0;

其中GLOBAL_PRIVATE是python進(jìn)行實(shí)現(xiàn)的,運(yùn)用python的宏定義(macro)來(lái)定義調(diào)用了C語(yǔ)言的CreateGlobalPrivateOwnSymbol方法。

macro GLOBAL_PRIVATE(name) = (%CreateGlobalPrivateOwnSymbol(name));

隨后運(yùn)用了一個(gè)自執(zhí)行的匿名函數(shù)進(jìn)行閉包邏輯。

(function() {
  // 主邏輯
})();

在閉包邏輯的最后,在promise原型上掛載了三個(gè)方法:chain,then,catch。在promise對(duì)象上掛載了all,race等六個(gè)方法。將Promise對(duì)象注冊(cè)到了global。

%AddNamedProperty(global, "Promise", $Promise, DONT_ENUM);
InstallFunctions($Promise, DONT_ENUM, [
    "defer", PromiseDeferred,
    "accept", PromiseResolved,
    "reject", PromiseRejected,
    "all", PromiseAll,
    "race", PromiseOne,
    "resolve", PromiseCast
]);
InstallFunctions($Promise.prototype, DONT_ENUM, [
    "chain", PromiseChain,
    "then", PromiseThen,
    "catch", PromiseCatch
]);
Start from constructor
var $Promise = function Promise(resolver) {
    // 如果傳入?yún)?shù)為全局promiseRaw變量的時(shí)候return
    if (resolver === promiseRaw) return;
    // 如果當(dāng)前函數(shù)不是構(gòu)造函數(shù)的化,拋出錯(cuò)誤這不是一個(gè)promise
    if (!%_IsConstructCall()) throw MakeTypeError("not_a_promise", [this]);
    // 如果傳入?yún)?shù)不是一個(gè)函數(shù)的話,拋出錯(cuò)誤,傳入?yún)?shù)不是一個(gè)function
    if (!IS_SPEC_FUNCTION(resolver))
        throw MakeTypeError("resolver_not_a_function", [resolver]);
    var promise = PromiseInit(this);
    try {
        // debug相關(guān)忽略
        %DebugPushPromise(promise);
        resolver(function(x) { PromiseResolve(promise, x) },
                 function(r) { PromiseReject(promise, r) });
    } catch (e) {
        // 報(bào)錯(cuò)之后走到錯(cuò)誤處理函數(shù)
        PromiseReject(promise, e);
    } finally {
        // debug相關(guān)忽略
        %DebugPopPromise();
    }
}

構(gòu)造函數(shù)在做完額外的異常和參數(shù)判斷后,進(jìn)入主邏輯調(diào)用PromiseInit方法初始化promise,隨后調(diào)用了resolver方法,傳入了兩個(gè)默認(rèn)的處理函數(shù)。在promise在內(nèi)部被調(diào)用時(shí)(PromiseDeferred方法被調(diào)用時(shí))會(huì)實(shí)例化$promise,將默認(rèn)方法return回去,使得創(chuàng)建的promise示例具有resolve和reject方法。

function PromiseDeferred() {
    if (this === $Promise) {
        // Optimized case, avoid extra closure.
        var promise = PromiseInit(new $Promise(promiseRaw));
        return {
            promise: promise,
            resolve: function(x) { PromiseResolve(promise, x) },
            reject: function(r) { PromiseReject(promise, r) }
        };
    } else {
        var result = {};
        result.promise = new this(function(resolve, reject) {
            result.resolve = resolve;
            result.reject = reject;
        })
        return result;
    }
}
PromiseInit
function PromiseSet(promise, status, value, onResolve, onReject) {
    // macro SET_PRIVATE(obj, sym, val) = (obj[sym] = val);
    // 設(shè)置promise的狀態(tài),SET_PRIVATE只有在給已經(jīng)存在的對(duì)象設(shè)置已有屬性值的時(shí)候才會(huì)被調(diào)用
    SET_PRIVATE(promise, promiseStatus, status);
    SET_PRIVATE(promise, promiseValue, value);
    SET_PRIVATE(promise, promiseOnResolve, onResolve);
    SET_PRIVATE(promise, promiseOnReject, onReject);
    // debug代碼忽略
    if (DEBUG_IS_ACTIVE) {
        %DebugPromiseEvent({ promise: promise, status: status, value: value });
    }
    return promise;
}

function PromiseInit(promise) {
    return PromiseSet(
        promise, 0, UNDEFINED, new InternalArray, new InternalArray)
}

實(shí)質(zhì)上是調(diào)用了PromiseSet方法給promise設(shè)置了當(dāng)前的狀態(tài)。

PromiseResolve

promiseResolve方法的調(diào)用暴露給外部的promise.accept(高版本為resolve)方法,如果當(dāng)前的this指向promise的構(gòu)造函數(shù),則設(shè)置當(dāng)前的promise狀態(tài),否則調(diào)用resolve函數(shù)執(zhí)行。

function PromiseResolved(x) {
    if (this === $Promise) {
        // Optimized case, avoid extra closure.
        return PromiseSet(new $Promise(promiseRaw), +1, x);
    } else {
        return new this(function(resolve, reject) { resolve(x) });
    }
}

promiseResolve處理邏輯同promiseReject,不再贅述。

promise.then

PromiseThen方法的調(diào)用暴露給實(shí)例化后的promise.then方法調(diào)用。

PromiseThen = function PromiseThen(onResolve, onReject) {
    onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve
    : PromiseIdResolveHandler;
    onReject = IS_SPEC_FUNCTION(onReject) ? onReject
    : PromiseIdRejectHandler;
    var that = this;
    var constructor = this.constructor;
    return %_CallFunction(
        this,
        function(x) {
            x = PromiseCoerce(constructor, x);
            return x === that ? onReject(MakeTypeError("promise_cyclic", [x])) :
            IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x);
        },
        onReject,
        PromiseChain
    );
}

首先判斷傳入的兩個(gè)參數(shù)是否是函數(shù),不是的話添加默認(rèn)的處理函數(shù),做良好的容錯(cuò)處理。而后調(diào)用了 %_CallFunction方法(第一個(gè)參數(shù)是this,最后一個(gè)參數(shù)是要調(diào)用的方法,中間是傳入?yún)?shù)),類似Function.prototype.call()方法,調(diào)用了PromiseChain方法,傳入了兩個(gè)參數(shù)resolve和reject。在resolve方法內(nèi)部調(diào)用了PromiseCoerce方法,生成對(duì)象如果是個(gè)thenable對(duì)象調(diào)用對(duì)象的then方法否則直接onResolve方法。

PromiseCoerce
function PromiseCoerce(constructor, x) {
    if (!IsPromise(x) && IS_SPEC_OBJECT(x)) {
        var then;
        try {
            then = x.then;
        } catch(r) {
            return %_CallFunction(constructor, r, PromiseRejected);
        }
        // macro IS_SPEC_FUNCTION(arg) = (%_ClassOf(arg) === "Function");
        // 如果是一個(gè)function
        if (IS_SPEC_FUNCTION(then)) {
            var deferred = %_CallFunction(constructor, PromiseDeferred);
            try {
                %_CallFunction(x, deferred.resolve, deferred.reject, then);
            } catch(r) {
                deferred.reject(r);
            }
            return deferred.promise;
        }
    }
    return x;
}

核心的邏輯是如果傳入對(duì)象的then屬性是一個(gè)function,則調(diào)用then方法。若有報(bào)錯(cuò)走到reject方法。

PromiseChain
PromiseChain = function PromiseChain(onResolve, onReject) {  
    // 補(bǔ)默認(rèn)的處理函數(shù)
    onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
    onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
    var deferred = %_CallFunction(this.constructor, PromiseDeferred);
    switch (GET_PRIVATE(this, promiseStatus)) {
        case UNDEFINED:
            throw MakeTypeError("not_a_promise", [this]);
        case 0:  // Pending
            GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred);
            GET_PRIVATE(this, promiseOnReject).push(onReject, deferred);
            break;
        case +1:  // Resolved
            PromiseEnqueue(GET_PRIVATE(this, promiseValue),
                           [onResolve, deferred],
                           +1);
            break;
        case -1:  // Rejected
            PromiseEnqueue(GET_PRIVATE(this, promiseValue),
                           [onReject, deferred],
                           -1);
            break;
    }
    // debug代碼忽略
    if (DEBUG_IS_ACTIVE) {
        %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
    }
    return deferred.promise;
}

PromiseChain方法是promise實(shí)現(xiàn)的核心,判斷當(dāng)前定義的promise狀態(tài),如果是pending狀態(tài)在promiseOnResolve數(shù)組中push當(dāng)前的onResolve方法。如果是Resolved狀態(tài)或者Rejected狀態(tài),則調(diào)用PromiseEnqueue函數(shù)進(jìn)行微任務(wù)的添加。

PromiseEnqueue
function PromiseEnqueue(value, tasks, status) {
    var id, name, instrumenting = DEBUG_IS_ACTIVE;
    %EnqueueMicrotask(function() {
        if (instrumenting) {
            %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
        }
        for (var i = 0; i < tasks.length; i += 2) {
            PromiseHandle(value, tasks[i], tasks[i + 1])
        }
        if (instrumenting) {
            %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
        }
    });
    if (instrumenting) {
        id = ++lastMicrotaskId;
        name = status > 0 ? "Promise.resolve" : "Promise.reject";
        %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
    }
}

? 此步驟其實(shí)是將PromiseHandle函數(shù)加入JS運(yùn)行時(shí)的微任務(wù)隊(duì)列中。微任務(wù)的隊(duì)列列表是C語(yǔ)言進(jìn)行維護(hù)的,應(yīng)用%EnqueueMicrotask方法進(jìn)行添加。

PromiseHandle
function PromiseHandle(value, handler, deferred) {
    try {
        %DebugPushPromise(deferred.promise);
        var result = handler(value);
        if (result === deferred.promise)
            throw MakeTypeError("promise_cyclic", [result]);
        else if (IsPromise(result))
            %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain);
        else
            deferred.resolve(result);
    } catch (exception) {
        try { deferred.reject(exception); } catch (e) { }
    } finally {
        %DebugPopPromise();
    }
}

此函數(shù)處理了傳入的方法,是指是調(diào)用了resolve方法,如果返回的結(jié)果依舊是一個(gè)promise則繼續(xù)調(diào)用PromiseChain方法,否則調(diào)用新生成的promise實(shí)例的resolve方法,進(jìn)而實(shí)現(xiàn)循壞調(diào)用。

promise.all

promise的all方法實(shí)現(xiàn)了發(fā)送多個(gè)promise請(qǐng)求,返回一個(gè)新的promise,所有promise打到resolve狀態(tài)時(shí)觸發(fā)resolve狀態(tài),若有一個(gè)promise被reject,則返回此promise的reject原因。

function PromiseAll(values) {
    var deferred = %_CallFunction(this, PromiseDeferred);
    var resolutions = [];
    if (!%_IsArray(values)) {
        deferred.reject(MakeTypeError("invalid_argument"));
        return deferred.promise;
    }
    try {
        var count = values.length;
        if (count === 0) {
            deferred.resolve(resolutions);
        } else {
            for (var i = 0; i < values.length; ++i) {
                this.resolve(values[i]).then(
                    (function() {
                        // Nested scope to get closure over current i (and avoid .bind).
                        // TODO(rossberg): Use for-let instead once available.
                        var i_captured = i;
                        return function(x) {
                            resolutions[i_captured] = x;
                            if (--count === 0) deferred.resolve(resolutions);
                        };
                    })(),
                    function(r) { deferred.reject(r) }
                );
            }
        }
    } catch (e) {
        deferred.reject(e)
    }
    return deferred.promise;
}

首先判斷傳參的合理性,生成一個(gè)新的promise對(duì)象,利用遍歷的方式給每個(gè)傳入的promise的resolve方法后都追加了then方法,使得每個(gè)傳入的promise執(zhí)行then方法后湊執(zhí)行判斷邏輯,當(dāng)計(jì)數(shù)count的flag為0的時(shí)候,所有promise resolve完成,調(diào)用新promise對(duì)象的resolve方法,傳入新promise的reject方法作為then方法reject參數(shù)。使得所有promise的reject函數(shù)被調(diào)用時(shí)都會(huì)走到新promise對(duì)象的reject,最后返回新生成的promise。

Summary

Promise的狀態(tài)和核心變量均托管到公共的作用域去維護(hù),通過(guò)數(shù)組的push方法去添加Promise自定的resolve和reject方法。并將resolve和reject方法的執(zhí)行加入微服務(wù)隊(duì)列中,等到resolve方法被調(diào)用時(shí)執(zhí)行resolve(value)方法進(jìn)行調(diào)用。為了實(shí)現(xiàn)promise的循環(huán)嵌套調(diào)用,在每次處理value之前將處理邏輯之上包裹了一層新的promise邏輯,類似(new promise()).then(resolve(value)),思路如下。

var ref = function (value) {
    if (value && value.then)
        return value;
    return {
        then: function (callback) {
            // 實(shí)例化一個(gè)新的promise
            var result = defer();
            // 進(jìn)入宏任務(wù)隊(duì)列
            enqueue(function () {
                result.resolve(callback(value));
            });
            return result.promise;
        }
    };
};
Reference

promise設(shè)計(jì)思想:https://github.com/kriskowal/...

JavaScript執(zhí)行機(jī)制:https://www.jianshu.com/p/17c...

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/109724.html

相關(guān)文章

  • JS引擎理解Await b()與Promise.then(b)的堆棧處理

    摘要:對(duì)于引擎來(lái)說(shuō),兩者獲取堆棧的方式是不同的。對(duì)于引擎來(lái)說(shuō),堆棧信息附加在了函數(shù)所返回的并在鏈中傳遞,這樣函數(shù)也能在需要的時(shí)候獲取堆棧信息。使用可以實(shí)時(shí)監(jiān)控線上應(yīng)用的錯(cuò)誤,并獲取完整的堆棧信息。 譯者按: Async/Await真的只是簡(jiǎn)單的語(yǔ)法糖嗎?No! 原文:Asynchronous stack traces: why await beats .then() 作者: Math...

    ziwenxie 評(píng)論0 收藏0
  • Promisify 的源碼解析

    摘要:參考文檔升級(jí)后的函數(shù)回調(diào)參數(shù)問(wèn)題中的使用方法和還是不一樣的源碼講解的內(nèi)部機(jī)制優(yōu)化相關(guān)內(nèi)容文章官方文檔簡(jiǎn)述使用過(guò)的都知道這個(gè)方法的作用,通過(guò)該方法會(huì)讓形式的函數(shù)風(fēng)格轉(zhuǎn)換成方法,可以認(rèn)為是一顆語(yǔ)法糖,例如接下來(lái)我們就分析一下這個(gè)的內(nèi)部流程。 參考文檔 升級(jí)bluebird 3后Promise.promisify的函數(shù)回調(diào)參數(shù)問(wèn)題:3中的使用方法和2還是不一樣的 How does Bl...

    gougoujiang 評(píng)論0 收藏0
  • 2017文章總結(jié)

    摘要:歡迎來(lái)我的個(gè)人站點(diǎn)性能優(yōu)化其他優(yōu)化瀏覽器關(guān)鍵渲染路徑開(kāi)啟性能優(yōu)化之旅高性能滾動(dòng)及頁(yè)面渲染優(yōu)化理論寫法對(duì)壓縮率的影響唯快不破應(yīng)用的個(gè)優(yōu)化步驟進(jìn)階鵝廠大神用直出實(shí)現(xiàn)網(wǎng)頁(yè)瞬開(kāi)緩存網(wǎng)頁(yè)性能管理詳解寫給后端程序員的緩存原理介紹年底補(bǔ)課緩存機(jī)制優(yōu)化動(dòng) 歡迎來(lái)我的個(gè)人站點(diǎn) 性能優(yōu)化 其他 優(yōu)化瀏覽器關(guān)鍵渲染路徑 - 開(kāi)啟性能優(yōu)化之旅 高性能滾動(dòng) scroll 及頁(yè)面渲染優(yōu)化 理論 | HTML寫法...

    dailybird 評(píng)論0 收藏0
  • 2017文章總結(jié)

    摘要:歡迎來(lái)我的個(gè)人站點(diǎn)性能優(yōu)化其他優(yōu)化瀏覽器關(guān)鍵渲染路徑開(kāi)啟性能優(yōu)化之旅高性能滾動(dòng)及頁(yè)面渲染優(yōu)化理論寫法對(duì)壓縮率的影響唯快不破應(yīng)用的個(gè)優(yōu)化步驟進(jìn)階鵝廠大神用直出實(shí)現(xiàn)網(wǎng)頁(yè)瞬開(kāi)緩存網(wǎng)頁(yè)性能管理詳解寫給后端程序員的緩存原理介紹年底補(bǔ)課緩存機(jī)制優(yōu)化動(dòng) 歡迎來(lái)我的個(gè)人站點(diǎn) 性能優(yōu)化 其他 優(yōu)化瀏覽器關(guān)鍵渲染路徑 - 開(kāi)啟性能優(yōu)化之旅 高性能滾動(dòng) scroll 及頁(yè)面渲染優(yōu)化 理論 | HTML寫法...

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

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

0條評(píng)論

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