从Google V8引擎理会Promise完成

从Google V8引擎理会Promise完成

​ 本文浏览的源码为Google V8 Engine v3.29.45,此版本的promise完成为js版本,在后续版本Google继承对其完成举行了处置惩罚。引入了es6语法等,在7.X版本迭代后,逐步迭代成了C版本完成。

​ 贴上源码地点:https://chromium.googlesource… 人人自发传送。

​ 代码中一切相似%functionName的函数均是C言语完成的运行时函数。

Define variables

起首定义了将要在JS作用域使用了一些变量,提高了编译器的效力。

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

随后定义了一些全局私有变量供应和C语音交互,用于保护Promise的状况和举行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举行完成的,运用python的宏定义(macro)来定义挪用了C言语的CreateGlobalPrivateOwnSymbol要领。

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

随后运用了一个自实行的匿名函数举行闭包逻辑。

(function() {
  // 主逻辑
})();

在闭包逻辑的末了,在promise原型上挂载了三个要领:chain,then,catch。在promise对象上挂载了all,race等六个要领。将Promise对象注册到了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) {
    // 假如传入参数为全局promiseRaw变量的时刻return
    if (resolver === promiseRaw) return;
    // 假如当前函数不是组织函数的化,抛出毛病这不是一个promise
    if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]);
    // 假如传入参数不是一个函数的话,抛出毛病,传入参数不是一个function
    if (!IS_SPEC_FUNCTION(resolver))
        throw MakeTypeError('resolver_not_a_function', [resolver]);
    var promise = PromiseInit(this);
    try {
        // debug相干疏忽
        %DebugPushPromise(promise);
        resolver(function(x) { PromiseResolve(promise, x) },
                 function(r) { PromiseReject(promise, r) });
    } catch (e) {
        // 报错以后走到毛病处置惩罚函数
        PromiseReject(promise, e);
    } finally {
        // debug相干疏忽
        %DebugPopPromise();
    }
}

组织函数在做完分外的非常和参数推断后,进入主逻辑挪用PromiseInit要领初始化promise,随后挪用了resolver要领,传入了两个默许的处置惩罚函数。在promise在内部被挪用时(PromiseDeferred要领被挪用时)会实例化$promise,将默许要领return归去,使得建立的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);
    // 设置promise的状况,SET_PRIVATE只要在给已存在的对象设置已有属性值的时刻才会被挪用
    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)
}

实质上是挪用了PromiseSet要领给promise设置了当前的状况。

PromiseResolve

promiseResolve要领的挪用暴露给外部的promise.accept(高版本为resolve)要领,假如当前的this指向promise的组织函数,则设置当前的promise状况,不然挪用resolve函数实行。

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要领的挪用暴露给实例化后的promise.then要领挪用。

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
    );
}

起首推断传入的两个参数是不是是函数,不是的话增加默许的处置惩罚函数,做优越的容错处置惩罚。然后挪用了 %_CallFunction要领(第一个参数是this,末了一个参数是要挪用的要领,中心是传入参数),相似Function.prototype.call()要领,挪用了PromiseChain要领,传入了两个参数resolve和reject。在resolve要领内部挪用了PromiseCoerce要领,天生对象假如是个thenable对象挪用对象的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');
        // 假如是一个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;
}

中心的逻辑是假如传入对象的then属性是一个function,则挪用then要领。如有报错走到reject要领。

PromiseChain

PromiseChain = function PromiseChain(onResolve, onReject) {  
    // 补默许的处置惩罚函数
    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完成的中心,推断当前定义的promise状况,假如是pending状况在promiseOnResolve数组中push当前的onResolve要领。假如是Resolved状况或许Rejected状况,则挪用PromiseEnqueue函数举行微使命的增加。

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 });
    }
}

​ 此步骤实际上是将PromiseHandle函数到场JS运行时的微使命行列中。微使命的行列列表是C言语举行保护的,运用%EnqueueMicrotask要领举行增加。

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();
    }
}

此函数处置惩罚了传入的要领,是指是挪用了resolve要领,假如返回的效果依旧是一个promise则继承挪用PromiseChain要领,不然挪用新天生的promise实例的resolve要领,进而完成循坏挪用。

promise.all

promise的all要领完成了发送多个promise要求,返回一个新的promise,一切promise打到resolve状况时触发resolve状况,如有一个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;
}

起首推断传参的合理性,天生一个新的promise对象,应用遍历的体式格局给每一个传入的promise的resolve要领后都追加了then要领,使得每一个传入的promise实行then要领后凑实行推断逻辑,当计数count的flag为0的时刻,一切promise resolve完成,挪用新promise对象的resolve要领,传入新promise的reject要领作为then要领reject参数。使得一切promise的reject函数被挪用时都邑走到新promise对象的reject,末了返回新天生的promise。

Summary

Promise的状况和中心变量均托管到大众的作用域去保护,经由过程数组的push要领去增加Promise自定的resolve和reject要领。并将resolve和reject要领的实行到场微服务行列中,比及resolve要领被挪用时实行resolve(value)要领举行挪用。为了完成promise的轮回嵌套挪用,在每次处置惩罚value之前将处置惩罚逻辑之上包裹了一层新的promise逻辑,相似(new promise()).then(resolve(value)),思绪以下。

var ref = function (value) {
    if (value && value.then)
        return value;
    return {
        then: function (callback) {
            // 实例化一个新的promise
            var result = defer();
            // 进入宏使命行列
            enqueue(function () {
                result.resolve(callback(value));
            });
            return result.promise;
        }
    };
};

Reference

promise设想头脑:https://github.com/kriskowal/…

JavaScript实行机制:https://www.jianshu.com/p/17c…

    原文作者:Distance
    原文地址: https://segmentfault.com/a/1190000019258738
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞