Анализ исходного кода Mobx один (наблюдаемый)

внешний интерфейс исходный код JavaScript MobX

объявление о работе

Дамы и господа, резюме можно отправлять на адрес ivanxjfan@tencent.com.

Пожалуйста, укажите имя резюме в формате: Имя-Должность-Рабочие годы-Место работы (например: Чжан Сан-Внешняя разработка-Пять лет-Чанша.pdf)


Компания:Тенсент

Место:Чанша

Позиция:разработчик веб-интерфейса

Рабочие обязанности:

Отвечает за системные исследования и разработку продуктов Tencent Cloud DNSPod, полные интерфейсные функции системы и реализацию внутреннего логического кода, а также обеспечивает качество продукта и прогресс в исследованиях и разработках.

профессиональные требования:

1. Степень бакалавра или выше, специальность компьютерная, опыт работы более 2 лет;

2. Владение Javascript, html, css и другими технологиями разработки интерфейса с прочной основой;

3. Знакомство с текущими основными интерфейсными фреймворками (react/vue и т. д.), приветствуется опыт разработки на React и Redux;

4. Знакомы с протоколами HTTP и TCP/IP, хорошо разбираетесь в вопросах безопасности и знакомы с общими стратегиями атак и защиты в сети;

5. Хорошие аналитические способности и навыки решения проблем, а также энтузиазм в обучении;

6. Приветствуется опыт разработки Node.js/PHP;

7. Предпочтение отдается разработчикам плагинов с опытом работы в WP или DZ

Примечание. Этот пост подготовлен дочерней компанией Tencent Group. сообщение"


Компания:Тенсент

Место:Штаб-квартира Tencent в Шэньчжэне

Позиция:Старший разработчик веб-интерфейса

Рабочие обязанности:

Отвечает за проектирование системной архитектуры и исследования и разработки продуктов Tencent Cloud Domain Name (DNSPod).

профессиональные требования:

1. Степень бакалавра или выше, специальность компьютерная, опыт работы не менее 5 лет;

2. Владение Javascript, html, css и другими технологиями разработки интерфейса с прочной основой;

3, знакомый с текущим основным потоком передней рамы (Rection / Vue и т. Д.), Там реагируют, предпочтительный опыт развития Redux является предпочтительным;

4. Знакомы с протоколами HTTP и TCP/IP, хорошо разбираетесь в вопросах безопасности и знакомы с общими стратегиями атак и защиты в области сетевой безопасности;

5. Хорошие аналитические способности и навыки решения проблем, а также энтузиазм в обучении;

6. Приветствуется опыт разработки Node.js/PHP;

предисловие

Найдено в gitMobxисходный код, обнаружил, что он используетTypeScriptНаписано, потому что у меня нет опыта проекта на Tymscrit, поэтому я сначала составлю его.JavaScript, поэтому мы можем запустить скрипт следующим образом или изCDNНепосредственно загрузить скомпилированный исходный код, мы можем выбратьumdКанонический сценарий:

  1. git clone git@github.com:mobxjs/mobx.git
  2. npm i
  3. npm run quick-build

я прямо изCDNскачал копиюисходный кодА потом проанализирован.

Demo

Сначала мы начнем с основногоDemoначать, см.MobxОсновное использование:

const addBtn = document.getElementById('add')
const minusBtn = document.getElementById('minus')
const incomeLabel = document.getElementById('incomeLabel')
const bankUser = mobx.observable({
    name: 'Ivan Fan',
    income: 3,
    debit: 2
});

const incomeDisposer = mobx.autorun(() => {
    incomeLabel.innerText = `Ivan Fan income is ${bankUser.income}`
})

addBtn.addEventListener('click', ()=> {
    bankUser.income ++
})
minusBtn.addEventListener('click', () => {
    bankUser.income --
})

Наш интерфейс очень прост, как показано на рисунке:

фигура 1 Две кнопки, одна метка В файле js мы добавили событие **click** к двум кнопкам, тело события очень простое `bankUser.income ++` `bankUser.income --`, правильно ` Свойство `доход` пользователя банка` является самовозрастающим или самоубывающим, что очень волшебно. Когда мы нажимаем соответствующую кнопку, содержимое метки в середине меняется. Но мы не оперировали содержимым **incomeLabel** в событии нажатия кнопки, но его содержимое менялось в реальном времени с событием нажатия. Причина в том, что только следующий код обрабатывает текст **incomeLabel**: ```` константный доходDisposer = mobx.autorun(() => { доходLabel.innerText = `Доход Ивана Фана составляет ${bankUser.income}` }) ```` Это самая простая и загадочная функция **Mobx**, и мы можем сначала начать вникать в нее.

observable

Из приведенного выше JS-файла мы находим, что он ссылаетсяmobxЭти два методаobservableа такжеautorun, да, есть два таких способа, пустьincomeLabelИзменения происходят в режиме реального времени при нажатии кнопки, поэтому далее мы проведем углубленный анализ этих двух методов, а в этой главе мы сначала проанализируем наблюдаемое. Давайте сначала откроем Mobxисходный код, если мы используемVscodeОткройте этот исходный код, мы можем использовать горячую клавишуCtrl + K Ctrl + 0Сложите код, затем откройте его и найдитеexports, мы можем увидеть, какие методы предоставляет mobx:

фигура 2 Раскрывает ряд методов, которыми мы воспользуемся позже.

наблюдаемый, в переводе на китайский языкнаблюдаемый, давайте сейчас отладим этот метод, мы можемconst bankUser = mobx.observable({Нажмите точку останова в этой строке, затемF11, вскочил и обнаружил, что исходный код соответствует методу createObservable, то есть для создания наблюдаемого объекта:

var observable$$1 = createObservable;
function createObservable(v, arg2, arg3) {
    if (typeof arguments[1] === "string") {
        return deepDecorator$$1.apply(null, arguments);
    }
    if (isObservable$$1(v))
        return v;
    var res = isPlainObject$$1(v)
        ? observable$$1.object(v, arg2, arg3)
        : Array.isArray(v)
            ? observable$$1.array(v, arg2)
            : isES6Map$$1(v)
                ? observable$$1.map(v, arg2)
                : v;
    if (res !== v)
        return res;
    // otherwise, just box it
    fail$$1(process.env.NODE_ENV !== "production" &&
        "The provided value could not be converted into an observable. If you want just create an observable reference to the object use 'observable.box(value)'");
}

Приведенный выше код очень прост, есть три параметра, но когда мы вызываем, значение передается в качестве параметра, поэтому нам пока нужно заботиться только о первом параметре r. Ниже приведена основная логика этой функции:

  1. Если второй переданный параметр является строкой, вызовите deepDecorator?1.apply(null, arguments);
  2. Определите, является ли первый параметр уже наблюдаемым объектом, если он уже является наблюдаемым объектом, верните объект напрямую
  3. Определите тип первого параметра, а затем вызовите разные методы.Всего их три типа: объект, массив, карта (тип данных ES Map), которые вызываются отдельно:observable?1.object, observable?1.array, observable?1.mapметод, что это наблюдаемое?1? на первой линииvar observable?1 = createObservable;Поверхность — это метод createObservable. Но этот метод состоит всего из нескольких строк кода, и в нем нет методов объекта, массива и карты.Мы обнаружили, что в этом методе естьobservableFactoriesObject, который является фабричным объектом, используемым для добавления методов в createObservable, который определяет эти три метода и проходит черезObject.keys(observableFactories).forEach(function (name) { return (observable?1[name] = observableFactories[name]); });

Поскольку в нашей демонстрации мы передаем объект, он вызоветobservable?1.objectметод, мы продолжим анализ этого метода, код выглядит следующим образом:

    object: function (props, decorators, options) {
        if (typeof arguments[1] === "string")
            incorrectlyUsedAsDecorator("object");
        var o = asCreateObservableOptions$$1(options);
        if (o.proxy === false) {
            return extendObservable$$1({}, props, decorators, o);
        }
        else {
            var defaultDecorator = getDefaultDecoratorFromObjectOptions$$1(o);
            var base = extendObservable$$1({}, undefined, undefined, o);
            var proxy = createDynamicObservableObject$$1(base);
            extendObservableObjectWithProperties$$1(proxy, props, decorators, defaultDecorator);
            return proxy;
        }
    },

var o = asCreateObservableOptions?1(options);Генерируется простой объект:

var defaultCreateObservableOptions$$1 = {
    deep: true,
    name: undefined,
    defaultDecorator: undefined,
    proxy: true
};

o.proxyценностьtrue, так пойдетelseЛогическая ветвь, так что давайте разберем по порядкуelseКаждый кусок кода в ветке.

  1. var defaultDecorator = getDefaultDecoratorFromObjectOptions?1(o);Это логика, связанная с декоратором, давайте сначала пропустим ее.
  2. var base = extendObservable?1({}, undefined, undefined, o);Объект o обрабатывается и становитсяSymbolтип данных.

Этот шаг очень важен, добавление$mobx?1(var $mobx?1 = Symbol("mobx administration");) свойство, значение которого равноObservableObjectAdministrationтип объекта, которыйwriteМетод будет использоваться в последующих вызовах для перехвата данных.

изображение 3
  1. var proxy = createDynamicObservableObject?1(base);Этот метод является наиболееосновной, Проксировать этот объект

Рисунок 4

свойства этого объектаget, set, has, deleteProperty, ownKeys, preventExtensionsМетод перехватывается прокси, этоMobxОсновная точка добавления данных о событиях.

  1. третья точкаproxyПо сути, он просто инициализирует простой прокси-объект, но не имеет никакого отношения к тому, что нам нужно наблюдатьtarget(то есть,mobx.observableОбъект, переданный методом, который необходимо наблюдать), связан,extendObservableObjectWithProperties?1(proxy, props, decorators, defaultDecorator);метод будет проходитьtargetсвойство, назначьте егоproxyобъект, то мыmobx.observableОбъекты в нем все проксируются, то есть реализован перехват атрибутных операций.

  2. в четвертой точкеextendObservableObjectWithProperties?1В методе в итоге будут обработаны свойства исходного объектаУкрасить, просматривая стек вызовов функции и, наконец, вызывая метод addObservableProp из ObservableObjectAdministration для каждогоpropName(Ключ исходного объекта) создает объект ObservableValue и сохраняет его в объекте ObservableObjectAdministration.valuesсередина

отРисунок 3обнаружил, что реальный перехват данныхobjectProxyTrapsПерехватчик, в следующей главе нам необходимо провести глубокий анализ этого перехватчика, уделив особое вниманиеget,setКак реализовать перехват данных.

  1. return proxy;В конечном итоге вернет объект, который был проксирован, заменив собственный объект.

Объект bankUser — это объект, который был проксирован и содержитSymbolНовое свойство типа.

const bankUser = mobx.observable({
    name: 'Ivan Fan',
    income: 3,
    debit: 2
});

Суммировать

  1. Наблюдаемый сначала проходит в примитивном объекте (можно передавать несколько типов данных:array, map, object, теперь анализируется только случай типа объекта)
  2. Создайте пустой объект Object и добавьте некоторые свойства по умолчанию (var base = extendObservable?1({}, undefined, undefined, o);), в том числеSymbolСвойство типа, значение которого равноObservableObjectAdministrationтип объекта.
  3. использовать этот объектES6Прокси проксируется и будет перехватывать некоторые операции со столбцами этого объекта (get, set...) var proxy = new Proxy(base, objectProxyTraps);
  4. Пройдите по исходному объекту и смонтируйте все его собственные свойства во вновь созданном пустом объекте.
  5. Возвращает обработанный объектbankUser
  6. Затем вы можете контролировать соответствующую работу этого объекта.
  7. Обрабатываемый объект показан на рисунке ниже, а объектом, с которым предстоит работать позже, является следующий объект, ноobservableНа самом деле метод выполняет только второй шаг (2) на следующем рисунке, атрибут наблюдателей третьего шага (3) по-прежнему является объектом Set без какого-либо значения при последующем анализе.autorunВ методе это будет включать, когда присваивать ему значение