предисловие
Привет всем, я Акула, я до сих пор помню день острой лапши6 компанийВ конце концов, вы отвергли всех мужчин с больших заводов? Верно. Ха-ха. Студенты, которые не понимают, могут прочитать эту статью.Интервью с 6 крупными заводами за один день - предложение здесьПоскольку друзья по группе уговаривали меня прийти на собеседование лицом к лицу, потому что некоторое время назад я был занят (на самом деле ленив), мы снова встретились после полуторамесячной задержки.Подробный ответСложность делится на три типа: легкий, средний и сложный.Вы можете проверить себя, не глядя на ответы.Текущие вопросы включают в себя (Byte Ali Meituan Shopee JD.com Xiaomi Dewu Tuhuи т. д.) Если у вас есть разные мнения по поводу ответа, добро пожаловать на обсуждение в области комментариев Наконец, вы можете нажатьСвязьПрисоединяйтесь к фронтенд-группе Brother Shark, заходите внутрь, обсуждайте технологии, трогайте рыбу, просите о помощи
Это непросто организовать. Если эта статья окажется вам полезной, помнитеКак СанлианБольшое спасибо!
Простой
1 Весь процесс от ввода URL-адреса до завершения рендеринга в браузере
Это классический вопрос, о котором часто говорят.Далее интервью.Простая версияотвечать
- Введите URL-адрес в адресную строку браузера и нажмите Enter.
- Браузер определяет, имеет ли текущий URL кеш, и сравнивает, истек ли срок действия кеша.
- IP-адрес, соответствующий URL-адресу разрешения DNS.
- Установить TCP-соединение на основе IP (трехстороннее рукопожатие)
- отправить http-запрос
- Сервер обрабатывает запрос, а браузер принимает HTTP-ответ.
- Браузер анализирует и отображает страницу
- Закрыть TCP-соединение (четырехстороннее рукопожатие)
Уведомление! Основываясь на этом вопросе, интервьюер может исследовать многие области знаний о интерфейсе: от знаний о сети http до принципов работы браузера и оптимизации производительности интерфейса — эту тему можно использовать в качестве введения.
Поэтому я рекомендую вам прочитать этот подробный ответСамые подробные классические вопросы для интервью в истории Что произошло с момента ввода URL до просмотра страницы?
2 Что такое делегирование событий (eventdelegation) и в чем преимущества
Принцип делегирования событий: вместо того, чтобы устанавливать прослушиватель событий для каждого дочернего узла отдельно, установите его на его родительском узле, а затем используйте принцип всплытия для установки каждого дочернего узла.
преимущество:
-
Сокращение потребления памяти и операций dom, повышение производительности В JavaScript количество обработчиков событий, добавленных на страницу, будет напрямую связано с общей производительностью страницы.Поскольку DOM необходимо постоянно манипулировать, более вероятно, что это вызовет перерисовку и перекомпоновку браузера, а также взаимодействие со страницей. событий тоже будет увеличиваться.чем длиннее становится,вот почемуСокращение операций с домомпричина. Каждый обработчик событий представляет собой объект с еще одним обработчиком событий,ОЗУзаймет больше места. Если вы хотите использовать делегирование событий, вы поместите все операции в программу js, будете работать только с ее родителем и будете взаимодействовать с dom только один раз, что может значительно сократить количество взаимодействий с dom и повысить производительность;
-
Динамически связывать события Поскольку событие привязано к родительскому элементу, новый добавленный элемент также может инициировать то же событие.
3 addEventListener захватывает или всплывает по умолчанию
По умолчаниюпузырь
addEventListenerтретий параметрПо умолчанию установлено значение false для выполнения всплывающего поведения событий.
При значении true выполняется поведение захвата событий.
4 Какова композиция слоя рендеринга css и как браузер создает новый слой рендеринга
Каждый узел в дереве DOM соответствует объекту рендеринга (RenderObject).Когда их объекты рендеринга находятся в одном координатном пространстве (пространстве по оси Z), формируется RenderLayers, который является слоем рендеринга. Слой рендеринга гарантирует, что элементы страницы расположены в правильном порядке, который появится, когдаСостав слоев (композит), который правильно обрабатывает отображение прозрачных и перекрывающихся элементов. Этот процесс особенно важен для страниц с перекрывающимися элементами, потому что, если слои объединены в неправильном порядке, элементы будут отображаться неправильно.
Как браузеры создают новые слои визуализации
-
документ корневого элемента
-
Иметь явные атрибуты позиционирования (относительное, фиксированное, липкое, абсолютное)
-
opacity < 1
-
Имеет свойство CSS fliter
-
Имеет свойство маски CSS
-
Имеет свойство CSS mix-blend-mode со значением, отличным от нормального
-
Имеет свойство преобразования CSS со значением, отличным от none
-
свойство backface-visibility скрыто
-
Имеет свойство отражения CSS
-
Имеет свойство CSS column-count со значением, отличным от auto, или свойство CSS column-width со значением, отличным от auto
-
В настоящее время применяются анимации для непрозрачности, преобразования, флитера, фонового фильтра.
-
перелив не виден
Уведомление! Многие люди будутУсловия для компоновки слоев и условия для рендеринга слоевПутаница, эти два условия возникают в двух разных ссылках обработки слоев, которые совершенно разные.Подробности см. в этой статье.Составление слоев браузера и оптимизация рендеринга страниц
5 различий между плагином webpack и загрузчиком
-
Загрузчик:
Используемый для преобразования исходного кода модуля, загрузчик описывает, как webpack обрабатывает модули без JavaScript, и вводит эти зависимости в buld. Загрузчики могут преобразовывать файлы с разных языков (например, TypeScript) в JavaScript или преобразовывать встроенные изображения в URL-адреса данных. Например: CSS-Loader, Style-Loader и т. д.
-
Plugin
Цель состоит в том, чтобы решить другие вещи, которые не могут достичь погрузчика, он действует непосредственно на WebPack и расширяет его функциональность. В течение жизненного цикла WebPack работает, многие события транслируются, и плагины могут прослушивать эти события и изменять результаты вывода через API, предоставляемые WebPack в соответствующее время. Плагины варьируются от оптимизации упаковки и сжатия до переопределения переменных в среде. Интерфейс плагина чрезвычайно мощный и может использоваться для решения самых разных задач.
Для знаний, связанных с WebPack, см. Эта статья Brother SharkПродвинутые высокооплачиваемые статьи Webpack, обязательные к просмотру.Это легко понять, и этого достаточно для простого интервью.
6. Разница между привязкой вызова
- Все три могут изменить this объект функции, на который указывает.
- Первый параметр из трех — это объект, на который будет указывать this.Если такого параметра нет или параметр не определен или имеет значение null, по умолчанию он будет указывать на глобальное окно.
- Все три можно пройти, ноприменить это массив,а такжевызов - это список параметров, а apply и call — это одноразовые входящие параметры, аbind можно разделить на несколько входящих.
- привязать, чтобы вернутьсяфункция после привязки этого, легко позвонить позже; подайте заявку и позвонитевыполнить немедленно.
- bind() вернет новую функцию, если возвращенная новая функцияКонструкторСоздайте новый объект, затем на этот разбольше не указываетВместо этого первый аргумент, переданный для связывания, указывает на экземпляр, созданный с помощью new.
Уведомление! Многие учащиеся могут игнорировать случай, когда функция bind-bound создается командой new в качестве конструктора.
7 Приведите примеры реального использования замыканий в сценариях
Например, обычное дросселирование с защитой от сотрясений.
// 防抖
function debounce(fn, delay = 300) {
let timer; //闭包引用的外界变量
return function () {
const args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
Использование замыканий для эмуляции области действия блока в JavaScript
function outputNumbers(count) {
(function () {
for (var i = 0; i < count; i++) {
alert(i);
}
})();
alert(i); //导致一个错误!
}
Замыкания могут использоваться для создания закрытых переменных в объектах.
var aaa = (function () {
var a = 1;
function bbb() {
a++;
console.log(a);
}
function ccc() {
a++;
console.log(a);
}
return {
b: bbb, //json结构
c: ccc,
};
})();
console.log(aaa.a); //undefined
aaa.b(); //2
aaa.c(); //3
8 CSS приоритет - это то, как рассчитать
- Первый приоритет: !important переопределяет стили элементов в любом месте страницы.
- 1. Встроенный стиль, такой как style="color: green", вес 1000
- 2. Селектор идентификатора, например #app, с весом 0100.
- 3. Класс, псевдокласс, селектор атрибутов, например .foo, :first-child, div[class="foo"], вес 0010
- 4. Метки, селекторы псевдоэлементов, такие как div::first-line, с весом 0001.
- 5. Подстановочные знаки, селекторы подклассов, селекторы одного уровня, такие как *, >, +, с весом 0000
- 6. Унаследованные стили не имеют веса
9 Темы, связанные с циклом обработки событий — необходимо проверить (обычно оценивают порядок вывода кода)
setTimeout(function () {
console.log("1");
}, 0);
async function async1() {
console.log("2");
const data = await async2();
console.log("3");
return data;
}
async function async2() {
return new Promise((resolve) => {
console.log("4");
resolve("async2的结果");
}).then((data) => {
console.log("5");
return data;
});
}
async1().then((data) => {
console.log("6");
console.log(data);
});
new Promise(function (resolve) {
console.log("7");
// resolve()
}).then(function () {
console.log("8");
});
Выходной результат: 247536 результат 1 async2
Уведомление! я последнийPromiseЯ закопал дыру и не вызывал метод разрешения. Я столкнулся с этим во время интервью с Meituan. В то время я не видел этого ясно. Я думал, что это та же рутина. Наконец, интервьюер сказал это был неправ.
10 код состояния http 204 301 302 304 400 401 403 404 Значение
- Код состояния http 204 (нет содержимого). Сервер успешно обработал запрос, но не вернул содержимого.
- Код состояния http 301 (Перемещено навсегда) Запрошенная веб-страница была окончательно перемещена в новое место. Когда сервер возвращает этот ответ (на запрос GET или HEAD), он автоматически перенаправляет запросчика в новое место.
- Код состояния http 302 (временно перемещен). В настоящее время сервер отвечает на запросы с веб-страницы из другого места, но инициатор запроса должен продолжать использовать исходное расположение для будущих запросов.
- Код состояния http 304 (без изменений) Запрошенная страница не была изменена с момента последнего запроса. Когда сервер возвращает этот ответ, содержимое веб-страницы не возвращается.
- Код состояния http 400 (неверный запрос) Сервер не понимает синтаксис запроса (обычно ошибка параметра).
- Код состояния http 401 (Неавторизованный) Запрос требует аутентификации. Сервер может вернуть этот ответ для веб-страниц, требующих входа в систему.
- Код состояния http 403 (Запрещено) Сервер отклонил запрос. (Как правило, полномочий пользователя клиента недостаточно)
- Код состояния http 404 (не найдено) Сервер не может найти запрошенную веб-страницу.
11 Какие улучшения были сделаны в http2.0 3.0?
Особенности http2.0 заключаются в следующем
- Двоичная кадровая передача
- мультиплексирование
- сжатие заголовка
- пуш сервера
Http3.0По сравнению с Http2.0 это новое изменение!
Протокол HTTP - это протокол уровня приложений, который построен на транспортном слое. Мы также знаем, что выше транспортного слоя нет протокола TCP, и есть еще одно мощное соглашение.UDP-протокол, 2.0 и 1.0 основаны на TCP, поэтому TCP будет иметь недостатки и ограничения. Http3.0 основан на UDP. Так что он качественно отличается от Http2.0.
Особенности http3.0 заключаются в следующем
- миграция соединения
- Нет блокировки в начале очереди
- Пользовательский контроль перегрузки
- Упреждающая безопасность и упреждающая коррекция ошибок
Рекомендуется внимательно прочитать эту статьюНекоторые мысли о Http2.0 и преимуществах Http3.0
12 Какие значения позиции и каковы функции?
-
static
static (без позиционирования) — это значение по умолчанию для позиции, и элемент находится в обычном потоке документа, игнорируя свойства левого, верхнего, правого, нижнего и z-index.
-
relative
Relative (относительное позиционирование) относится к установке позиционирования элемента относительно исходного положения.Элемент не отклоняется от потока документа, поэтому исходное положение элемента будет сохранено, а положение других элементов не будет затронуто .
сцены, которые будут использоваться: дочерний элемент позиционируется относительно родительского элемента
-
абсолютный Абсолютное (абсолютное позиционирование) относится к установке абсолютного позиционирования для элементов.Относительно расположенные объекты можно разделить на две ситуации:
- Если элемент с абсолютным значением установлен, если есть элемент-предок, для атрибута позиции которого задано относительное или абсолютное значение, то объектом позиционирования элемента будет элемент-предок, атрибут позиции которого был установлен.
- Если нет элемента-предка с установленным атрибутом position, он в это время позиционируется относительно тела.сцены, которые будут использоваться: Следуйте за значком. Значок позиционируется с использованием свойств absolute и margin, которые не зависят от родительского элемента позиционирования, поэтому при изменении количества символов в тексте положение значка можно адаптировать.
-
фиксированный Можно просто сказать, что fixed — это особая версия absolute, фиксированные элементы всегда позиционируются относительно тела.сцены, которые будут использоваться: боковая панель или рекламное изображение
-
наследовать Наследовать свойство position родительского элемента, но следует отметить, что IE8 и предыдущие версии не поддерживают свойство наследования.
-
липкий Когда установлен липкий элемент, положение элемента не зависит от положения в диапазоне экрана (окне просмотра) (такие свойства, как top и left, недействительны). диапазон смещения, позиционирование станет фиксированным в соответствии с установленными левым, верхним и другими свойствами в эффект фиксированного положения. Когда элемент прокручивается в контейнере за пределы указанного значения смещения, элемент фиксируется в указанной позиции в контейнере. То есть, если вы установите top: 50px, то когда липкий элемент достигнет позиции в 50px от вершины относительно позиционированного элемента, он будет зафиксирован и больше не будет двигаться вверх (эквивалентно фиксированному позиционированию в настоящее время).
сцены, которые будут использоваться: следить за окном
13 Реализация вертикального и горизонтального центрирования
Этот вопрос в основном является классическим вопросом CSS, но в Интернете уже слишком много готовых ответов.Если вы хотите добавить баллы к этому вопросу
Можно реализовать множество различных схем для фиксированной ширины и высоты и переменной ширины и высоты.
предлагаю посмотреть прямоИнтервьюер: Сколько горизонтальных и вертикальных макетов по центру вы можете создать (фиксированная ширина и высота и переменная ширина и высота)
14 Каковы методы связи компонентов vue
-
родительские компоненты props и $emit передают данные дочерним компонентам через реквизиты, а дочерние компоненты передают данные родительским компонентам через события запуска $emit
-
$parent,$children Получить родительский компонент текущего компонента и дочерние компоненты текущего компонента
-
$attrs и $listeners A->B->C. Vue 2.4 предоставляет $attrs и $listeners для решения этой проблемы.
-
Переменные предоставляются путем предоставления в родительском компоненте, а затем внедряются в дочерний компонент посредством инъекции. (Официально не рекомендуется для использования в реальном бизнесе, но обычно используется при написании библиотек компонентов)
-
$refs получить экземпляр компонента
-
Передача данных компонентов брата envetBus В этом случае вы можете использовать метод шины событий
-
vuex управление состоянием
15 принципов адаптивного дизайна Vue
Общая идея — захват данных + режим наблюдателя.
Внутри объекта метод defineReactive используется для захвата свойств с помощью Object.defineProperty (захватываются только существующие свойства), а массив реализуется путем переопределения метода массива. Когда страница использует соответствующий атрибут, каждый атрибут имеет свой собственный атрибут dep, в котором хранится наблюдатель, от которого он зависит (коллекция зависимостей).При изменении атрибута он уведомляет соответствующий наблюдатель об обновлении (распространении обновления).
Соответствующий код выглядит следующим образом
class Observer {
// 观测值
constructor(value) {
this.walk(value);
}
walk(data) {
// 对象上的所有属性依次进行观测
let keys = Object.keys(data);
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
let value = data[key];
defineReactive(data, key, value);
}
}
}
// Object.defineProperty数据劫持核心 兼容性在ie9以及以上
function defineReactive(data, key, value) {
observe(value); // 递归关键
// --如果value还是一个对象会继续走一遍odefineReactive 层层遍历一直到value不是对象才停止
// 思考?如果Vue数据嵌套层级过深 >>性能会受影响
Object.defineProperty(data, key, {
get() {
console.log("获取值");
//需要做依赖收集过程 这里代码没写出来
return value;
},
set(newValue) {
if (newValue === value) return;
console.log("设置值");
//需要做派发更新过程 这里代码没写出来
value = newValue;
},
});
}
export function observe(value) {
// 如果传过来的是对象或者数组 进行属性劫持
if (
Object.prototype.toString.call(value) === "[object Object]" ||
Array.isArray(value)
) {
return new Observer(value);
}
}
Подробное объяснение принципа адаптивных данныхпортал
16 Принцип Vue nextTick
Обратные вызовы в nextTick — это отложенные обратные вызовы, которые выполняются после окончания следующего цикла обновления DOM. Используйте этот метод сразу после изменения данных, чтобы получить обновленную модель DOM. Основная идея состоит в том, чтобы вызвать асинхронный метод микрозадачным способом для выполнения метода упаковки nextTick.
Соответствующий код выглядит следующим образом
let callbacks = [];
let pending = false;
function flushCallbacks() {
pending = false; //把标志还原为false
// 依次执行回调
for (let i = 0; i < callbacks.length; i++) {
callbacks[i]();
}
}
let timerFunc; //定义异步方法 采用优雅降级
if (typeof Promise !== "undefined") {
// 如果支持promise
const p = Promise.resolve();
timerFunc = () => {
p.then(flushCallbacks);
};
} else if (typeof MutationObserver !== "undefined") {
// MutationObserver 主要是监听dom变化 也是一个异步方法
let counter = 1;
const observer = new MutationObserver(flushCallbacks);
const textNode = document.createTextNode(String(counter));
observer.observe(textNode, {
characterData: true,
});
timerFunc = () => {
counter = (counter + 1) % 2;
textNode.data = String(counter);
};
} else if (typeof setImmediate !== "undefined") {
// 如果前面都不支持 判断setImmediate
timerFunc = () => {
setImmediate(flushCallbacks);
};
} else {
// 最后降级采用setTimeout
timerFunc = () => {
setTimeout(flushCallbacks, 0);
};
}
export function nextTick(cb) {
// 除了渲染watcher 还有用户自己手动调用的nextTick 一起被收集到数组
callbacks.push(cb);
if (!pending) {
// 如果多次调用nextTick 只会执行一次异步 等异步队列清空之后再把标志变为false
pending = true;
timerFunc();
}
}
Подробное объяснение принципа nextTickпортал
17 vue diff принцип
Рекомендуется смотреть непосредственно на подробное объяснение алгоритма diffпортал
18 Принцип маршрутизации Характеристики исторических и хэш-методов маршрутизации
хэш-режим
-
Значение location.hash на самом деле стоит после # в URL-адресе.Его характеристики таковы: хотя хэш появляется в URL-адресе, он не будет включен в HTTP-запрос и не повлияет на серверную часть, поэтому изменение хеша не перезагружать страницу.
-
Вы можете добавить события прослушивателя для изменений хэша
window.addEventListener("hashchange", funcRef, false);
Каждый раз, когда хэш (window.location.hash) изменяется, в историю доступа браузера будет добавляться запись.Используя указанные выше характеристики хэша, интерфейсная функция маршрутизации «обновление представления без повторного запроса страницы» можно реализовать.
Особенности: хорошая совместимость, но не красивая
режим истории
Воспользуйтесь преимуществами новых методов pushState() и replaceState() в интерфейсе истории HTML5.
Эти два метода применяются к станции истории браузера.На основе существующих назад, вперед и вперед они обеспечивают функцию модификации истории. У этих двух методов есть общая черта: когда они вызываются для изменения стека истории браузера, хотя текущий URL-адрес изменился, браузер не будет обновлять страницу. «Страница» обеспечивает основу.
Особенности: Хоть и красиво, но в рефреше появится 404, а бэкенд надо настраивать
19 рукописный переплет
//bind实现要复杂一点 因为他考虑的情况比较多 还要涉及到参数合并(类似函数柯里化)
Function.prototype.myBind = function (context, ...args) {
if (!context || context === null) {
context = window;
}
// 创造唯一的key值 作为我们构造的context内部方法名
let fn = Symbol();
context[fn] = this;
let _this = this;
// bind情况要复杂一点
const result = function (...innerArgs) {
// 第一种情况 :若是将 bind 绑定之后的函数当作构造函数,通过 new 操作符使用,则不绑定传入的 this,而是将 this 指向实例化出来的对象
// 此时由于new操作符作用 this指向result实例对象 而result又继承自传入的_this 根据原型链知识可得出以下结论
// this.__proto__ === result.prototype //this instanceof result =>true
// this.__proto__.__proto__ === result.prototype.__proto__ === _this.prototype; //this instanceof _this =>true
if (this instanceof _this === true) {
// 此时this指向指向result的实例 这时候不需要改变this指向
this[fn] = _this;
this[fn](...[...args, ...innerArgs]); //这里使用es6的方法让bind支持参数合并
delete this[fn];
} else {
// 如果只是作为普通函数调用 那就很简单了 直接改变this指向为传入的context
context[fn](...[...args, ...innerArgs]);
delete context[fn];
}
};
// 如果绑定的是构造函数 那么需要继承构造函数原型属性和方法
// 实现继承的方式: 使用Object.create
result.prototype = Object.create(this.prototype);
return result;
};
//用法如下
// function Person(name, age) {
// console.log(name); //'我是参数传进来的name'
// console.log(age); //'我是参数传进来的age'
// console.log(this); //构造函数this指向实例对象
// }
// // 构造函数原型的方法
// Person.prototype.say = function() {
// console.log(123);
// }
// let obj = {
// objName: '我是obj传进来的name',
// objAge: '我是obj传进来的age'
// }
// // 普通函数
// function normalFun(name, age) {
// console.log(name); //'我是参数传进来的name'
// console.log(age); //'我是参数传进来的age'
// console.log(this); //普通函数this指向绑定bind的第一个参数 也就是例子中的obj
// console.log(this.objName); //'我是obj传进来的name'
// console.log(this.objAge); //'我是obj传进来的age'
// }
// 先测试作为构造函数调用
// let bindFun = Person.myBind(obj, '我是参数传进来的name')
// let a = new bindFun('我是参数传进来的age')
// a.say() //123
// 再测试作为普通函数调用
// let bindFun = normalFun.myBind(obj, '我是参数传进来的name')
// bindFun('我是参数传进来的age')
19 Рукописное обещание. все и раса (Jingdong)
//静态方法
static all(promiseArr) {
let result = [];
//声明一个计数器 每一个promise返回就加一
let count = 0;
return new Mypromise((resolve, reject) => {
for (let i = 0; i < promiseArr.length; i++) {
//这里用 Promise.resolve包装一下 防止不是Promise类型传进来
Promise.resolve(promiseArr[i]).then(
(res) => {
//这里不能直接push数组 因为要控制顺序一一对应(感谢评论区指正)
result[i] = res;
count++;
//只有全部的promise执行成功之后才resolve出去
if (count === promiseArr.length) {
resolve(result);
}
},
(err) => {
reject(err);
}
);
}
});
}
//静态方法
static race(promiseArr) {
return new Mypromise((resolve, reject) => {
for (let i = 0; i < promiseArr.length; i++) {
Promise.resolve(promiseArr[i]).then(
(res) => {
//promise数组只要有任何一个promise 状态变更 就可以返回
resolve(res);
},
(err) => {
reject(err);
}
);
}
});
}
}
20 Рукописный текст — реализация паразитного композиционного наследования
function Parent(name) {
this.name = name;
this.say = () => {
console.log(111);
};
}
Parent.prototype.play = () => {
console.log(222);
};
function Children(name) {
Parent.call(this);
this.name = name;
}
Children.prototype = Object.create(Parent.prototype);
Children.prototype.constructor = Children;
// let child = new Children("111");
// // console.log(child.name);
// // child.say();
// // child.play();
21 Рукописный -новый оператор
function myNew(fn, ...args) {
let obj = Object.create(fn.prototype);
let res = fn.call(obj, ...args);
if (res && (typeof res === "object" || typeof res === "function")) {
return res;
}
return obj;
}
用法如下:
// // function Person(name, age) {
// // this.name = name;
// // this.age = age;
// // }
// // Person.prototype.say = function() {
// // console.log(this.age);
// // };
// // let p1 = myNew(Person, "lihua", 18);
// // console.log(p1.name);
// // console.log(p1);
// // p1.say();
22 Реализация имитации рукописного setTimeout setInterval (Ali)
function mySetInterval(fn, time = 1000) {
let timer = null,
isClear = false;
function interval() {
if (isClear) {
isClear = false;
clearTimeout(timer);
return;
}
fn();
timer = setTimeout(interval, time);
}
timer = setTimeout(interval, time);
return () => {
isClear = true;
};
}
// let a = mySettimeout(() => {
// console.log(111);
// }, 1000)
// let cancel = mySettimeout(() => {
// console.log(222)
// }, 1000)
// cancel()
23 Режим рукописного ввода-публикации-подписки (байты)
class EventEmitter {
constructor() {
this.events = {};
}
// 实现订阅
on(type, callBack) {
if (!this.events[type]) {
this.events[type] = [callBack];
} else {
this.events[type].push(callBack);
}
}
// 删除订阅
off(type, callBack) {
if (!this.events[type]) return;
this.events[type] = this.events[type].filter((item) => {
return item !== callBack;
});
}
// 只执行一次订阅事件
once(type, callBack) {
function fn() {
callBack();
this.off(type, fn);
}
this.on(type, fn);
}
// 触发事件
emit(type, ...rest) {
this.events[type] &&
this.events[type].forEach((fn) => fn.apply(this, rest));
}
}
// 使用如下
// const event = new EventEmitter();
// const handle = (...rest) => {
// console.log(rest);
// };
// event.on("click", handle);
// event.emit("click", 1, 2, 3, 4);
// event.off("click", handle);
// event.emit("click", 1, 2);
// event.once("dbClick", () => {
// console.log(123456);
// });
// event.emit("dbClick");
// event.emit("dbClick");
24 Рукописный ввод — регулирование с защитой от сотрясений (Jingdong)
// 防抖
function debounce(fn, delay = 300) {
//默认300毫秒
let timer;
return function () {
const args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, args); // 改变this指向为调用debounce所指的对象
}, delay);
};
}
window.addEventListener(
"scroll",
debounce(() => {
console.log(111);
}, 1000)
);
// 节流
// 设置一个标志
function throttle(fn, delay) {
let flag = true;
return () => {
if (!flag) return;
flag = false;
timer = setTimeout(() => {
fn();
flag = true;
}, delay);
};
}
window.addEventListener(
"scroll",
throttle(() => {
console.log(111);
}, 1000)
);
25 Рукописный ввод - конвертировать виртуальный дом в настоящий дом (аналогичные вопросы рекурсии - обязательны)
{
tag: 'DIV',
attrs:{
id:'app'
},
children: [
{
tag: 'SPAN',
children: [
{ tag: 'A', children: [] }
]
},
{
tag: 'SPAN',
children: [
{ tag: 'A', children: [] },
{ tag: 'A', children: [] }
]
}
]
}
把上诉虚拟Dom转化成下方真实Dom
<div id="app">
<span>
<a></a>
</span>
<span>
<a></a>
<a></a>
</span>
</div>
Отвечать
// 真正的渲染函数
function _render(vnode) {
// 如果是数字类型转化为字符串
if (typeof vnode === "number") {
vnode = String(vnode);
}
// 字符串类型直接就是文本节点
if (typeof vnode === "string") {
return document.createTextNode(vnode);
}
// 普通DOM
const dom = document.createElement(vnode.tag);
if (vnode.attrs) {
// 遍历属性
Object.keys(vnode.attrs).forEach((key) => {
const value = vnode.attrs[key];
dom.setAttribute(key, value);
});
}
// 子数组进行递归操作 这一步是关键
vnode.children.forEach((child) => dom.appendChild(_render(child)));
return dom;
}
26 Рукописный ввод-реализация метода сглаживания объекта (Али)
Описание темы
const obj = {
a: {
b: 1,
c: 2,
d: {e: 5}
},
b: [1, 3, {a: 2, b: 3}],
c: 3
}
flatten(obj) 结果返回如下
// {
// 'a.b': 1,
// 'a.c': 2,
// 'a.d.e': 5,
// 'b[0]': 1,
// 'b[1]': 3,
// 'b[2].a': 2,
// 'b[2].b': 3
// c: 3
// }
Отвечать
function isObject(val) {
return typeof val === "object" && val !== null;
}
function flatten(obj) {
if (!isObject(obj)) {
return;
}
let res = {};
const dfs = (cur, prefix) => {
if (isObject(cur)) {
if (Array.isArray(cur)) {
cur.forEach((item, index) => {
dfs(item, `${prefix}[${index}]`);
});
} else {
for (let k in cur) {
dfs(cur[k], `${prefix}${prefix ? "." : ""}${k}`);
}
}
} else {
res[prefix] = cur;
}
};
dfs(obj, "");
return res;
}
flatten();
27 Проверка правильности строки скобок от руки (Xiaomi)
Описание темы
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
示例 1:
输入:s = "()"
输出:true
示例 2:
输入:s = "()[]{}"
输出:true
示例 3:
输入:s = "(]"
输出:false
Отвечать
const isValid = function (s) {
if (s.length % 2 === 1) {
return false;
}
const regObj = {
"{": "}",
"(": ")",
"[": "]",
};
let stack = [];
for (let i = 0; i < s.length; i++) {
if (s[i] === "{" || s[i] === "(" || s[i] === "[") {
stack.push(s[i]);
} else {
const cur = stack.pop();
if (s[i] !== regObj[cur]) {
return false;
}
}
}
if (stack.length) {
return false;
}
return true;
};
28 Рукописный ввод - найти общий префикс массива (Meituan)
Описание темы
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。
示例 1:
输入:strs = ["flower","flow","flight"]
输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。
Отвечать
const longestCommonPrefix = function (strs) {
const str = strs[0];
let index = 0;
while (index < str.length) {
const strCur = str.slice(0, index + 1);
for (let i = 0; i < strs.length; i++) {
if (!strs[i] || !strs[i].startsWith(strCur)) {
return str.slice(0, index);
}
}
index++;
}
return str;
};
29 почерк - самая длинная не повторяющаяся подстрока строки
Описание темы
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
示例 4:
输入: s = ""
输出: 0
Отвечать
const lengthOfLongestSubstring = function (s) {
if (s.length === 0) {
return 0;
}
let left = 0;
let right = 1;
let max = 0;
while (right <= s.length) {
let lr = s.slice(left, right);
const index = lr.indexOf(s[right]);
if (index > -1) {
left = index + left + 1;
} else {
lr = s.slice(left, right + 1);
max = Math.max(max, lr.length);
}
right++;
}
return max;
};
30 Рукописный ввод - Как найти первое наименьшее положительное целое число, не встречающееся в массиве Как оптимизировать (байты)
给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
示例 1:
输入:nums = [1,2,0]
输出:3
示例 2:
输入:nums = [3,4,-1,1]
输出:2
示例 3:
输入:nums = [7,8,9,11,12]
输出:1
Это проблема байтового алгоритма, целью которой является постоянная оптимизация идеи алгоритма.
- первое издание Метод O (n ^ 2)
const firstMissingPositive = (nums) => {
let i = 0;
let res = 1;
while (i < nums.length) {
if (nums[i] == res) {
res++;
i = 0;
} else {
i++;
}
}
return res;
};
- второе издание И время, и пространство равны O(n)
const firstMissingPositive = (nums) => {
const set = new Set();
for (let i = 0; i < nums.length; i++) {
set.add(nums[i]);
}
for (let i = 1; i <= nums.length + 1; i++) {
if (!set.has(i)) {
return i;
}
}
};
- Окончательный версия Временная сложность составляет O (n), и используется только постоянное пространство уровней.
const firstMissingPositive = (nums) => {
for (let i = 0; i < nums.length; i++) {
while (
nums[i] >= 1 &&
nums[i] <= nums.length && // 对1~nums.length范围内的元素进行安排
nums[nums[i] - 1] !== nums[i] // 已经出现在理想位置的,就不用交换
) {
const temp = nums[nums[i] - 1]; // 交换
nums[nums[i] - 1] = nums[i];
nums[i] = temp;
}
}
// 现在期待的是 [1,2,3,...],如果遍历到不是放着该放的元素
for (let i = 0; i < nums.length; i++) {
if (nums[i] != i + 1) {
return i + 1;
}
}
return nums.length + 1; // 发现元素 1~nums.length 占满了数组,一个没缺
};
31 Рукописный ввод - как сгенерировать неповторяющийся случайный массив длины n в указанном источнике данных.Существует несколько методов и временная сложность (байты)
- первое издание Временная сложность O (n ^ 2)
function getTenNum(testArray, n) {
let result = [];
for (let i = 0; i < n; ++i) {
const random = Math.floor(Math.random() * testArray.length);
const cur = testArray[random];
if (result.includes(cur)) {
i--;
break;
}
result.push(cur);
}
return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 10);
- второе издание Обозначение/Пользовательские атрибуты Временная сложность O (n)
function getTenNum(testArray, n) {
let hash = {};
let result = [];
let ranNum = n;
while (ranNum > 0) {
const ran = Math.floor(Math.random() * testArray.length);
if (!hash[ran]) {
hash[ran] = true;
result.push(ran);
ranNum--;
}
}
return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 10);
- Третье издание метод обмена Временная сложность O (n)
function getTenNum(testArray, n) {
const cloneArr = [...testArray];
let result = [];
for (let i = 0; i < n; i++) {
debugger;
const ran = Math.floor(Math.random() * (cloneArr.length - i));
result.push(cloneArr[ran]);
cloneArr[ran] = cloneArr[cloneArr.length - i - 1];
}
return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 14);
Стоит отметить, что при работе с массивами используется метод обмена, эта идея очень распространена в алгоритмах.
- Окончательный версия удалить при обходе Временная сложность O (n)
function getTenNum(testArray, n) {
const cloneArr = [...testArray];
let result = [];
for (let i = 0; i < n; ++i) {
const random = Math.floor(Math.random() * cloneArr.length);
const cur = cloneArr[random];
result.push(cur);
cloneArr.splice(random, 1);
}
return result;
}
const testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const resArr = getTenNum(testArray, 14);
Средняя
1 Какие методы оптимизации есть в Webpack?
По мере того, как проект становится все больше и больше, скорость создания Webpack может становиться все медленнее и медленнее, а размер создаваемых js также будет становиться все больше и больше.В настоящее время необходимо оптимизировать конфигурацию Webpack.
Этот пункт знаний можно открыть в отдельной статье, пожалуйста, прочтитеПозвольте вам глубоко разблокировать серию Webpack (оптимизация)
2 Как включить аппаратное ускорение (GPU ускорение) в css
Когда браузер обрабатывает следующий css, он будет использовать рендеринг GPU.
- преобразование (ускорение графического процессора используется при появлении стилей 3D-преобразования)
- opacity
- filter
- will-change
采用 transform: translateZ(0)
采用 transform: translate3d(0, 0, 0)
使用 CSS 的 will-change属性。 will-change 可以设置为opacity、transform、top、left、bottom、right。
Уведомление! Взрыв слоя по некоторым причинам может привести к большому количеству синтетических слоев, которые не ожидаются. Элементы, которые не нужно повышать до составных слоев, становятся составными слоями из-за неправильного обращения). Чтобы решить проблему взрыва слоя, лучшим решением является нарушение условия перекрытия, что означает, что другие элементы не перекрываются с элементами составного слоя. Простой и прямой способ: при использовании аппаратного 3D-ускорения для повышения производительности анимации лучше всего добавить к элементу атрибут z-index и искусственно помешать сортировке композиции, что может эффективно уменьшить создание ненужных слоев композиции и улучшить производительность рендеринга, особенно для оптимизации мобильного терминала.
3 Каковы общие шаблоны проектирования и примеры сценариев использования
1. Фабричный шаблон — создайте экземпляр, передав параметры
Виртуальный DOM возвращает Vnode базовой метки и Vnode компонента в соответствии с различными параметрами.
2. Паттерн Singleton — вся программа имеет один и только один экземпляр
Метод регистрации плагина устанавливает vuex и vue-router, если в системе есть экземпляр, он вернется напрямую.
3. Режим публикации-подписки (механизм событий vue)
4. Шаблон наблюдателя (принцип реактивных данных)
5. Режим оформления: (использование декоратора @)
6. Паттерн стратегии Паттерн стратегии означает, что объект имеет определенное поведение, но в разных сценариях поведение имеет разные схемы реализации — например, стратегия слияния вариантов
... другие режимы приветствуются
4 Какова политика кэширования браузера (сильный кэш согласования кэша) Каков конкретный процесс?
Это тоже классическая проблема фронтенд-кэша, очки знаний складываются в статью, всем рекомендую прочитать.Сортировка знаний в кеше внешнего интерфейса браузера
5 Что такое процесс шифрования https
Используется смесь симметричного и асимметричного шифрования.
Пожалуйста, ознакомьтесь с конкретным процессомПередовые высокооплачиваемые статьи, обязательные для просмотра по HTTPS
6 Из каких свойств состоит flex:1?
flex на самом деле является аббревиатурой трех свойств flex-grow, flex-shrink и flex-basis.
flex-grow: определяет коэффициент увеличения элемента;
默认为0,即 即使存在剩余空间,也不会放大;
所有项目的flex-grow为1:等分剩余空间(自动放大占位);
flex-grow为n的项目,占据的空间(放大的比例)是flex-grow为1的n倍。
flex-shrink: определяет коэффициент уменьшения элемента;
默认为1,即 如果空间不足,该项目将缩小;
所有项目的flex-shrink为1:当空间不足时,缩小的比例相同;
flex-shrink为0:空间不足时,该项目不会缩小;
flex-shrink为n的项目,空间不足时缩小的比例是flex-shrink为1的n倍。
flex-basis: определяет пространство главной оси (основной размер), занимаемое элементом, перед выделением лишнего пространства Браузер вычисляет, есть ли лишнее пространство на главной оси в соответствии с этим свойством
默认值为auto,即 项目原本大小;
设置后项目将占据固定空间。
7 304 Что означает 304. Какова общая сцена и какой код состояния возвращается при попадании в надежный кэш?
Согласовать попадание в кеш и вернуть 304
Этот метод использует два поля в заголовке запроса заголовков: Last-Modified и If-Modified-Since. Сервер сообщает браузеру, когда ресурс был изменен в последний раз, через заголовок ответа Last-Modified:
Last-Modified: Thu, 20 Jun 2019 15:58:05 GMT
Когда ресурс запрашивается снова, браузер должен снова подтвердить серверу, истек ли срок действия ресурса.Учетные данные — это поле If-Modified-Since заголовка запроса, а значение — значение поля Last-Modified заголовок ответа в последнем запросе:
If-Modified-Since: Thu, 20 Jun 2019 15:58:05 GMT
Когда браузер отправляет запрос, сервер проверяет If-modified-Since в заголовке запроса, если время последней модификации совпадает, он возвращает 304. В противном случае добавляет last-Modified в заголовок ответа и возвращает данные ( тело ответа).
Кроме того, когда браузер отправляет запрос, сервер проверяет значение if-none-match в заголовке запроса и содержимое текущего файла, сгенерированного алгоритмом хеширования (например, nodejs: cryto.createHash('sha1') ) Сравнение символов сводки содержимого, если то же самое, вернуть 304 напрямую, в противном случае добавить атрибут etag в заголовок возврата (заголовок ответа) в качестве текущего символа сводки содержимого и вернуть содержимое.
В итоге:
请求头last-modified的日期与响应头的last-modified一致
请求头if-none-match的hash与响应头的etag一致
这两种情况会返回Status Code: 304
Сильное попадание в кеш возвращает 200200 (из кеша)
8 Рукописная реализация Vue.extend
// src/global-api/initExtend.js
import { mergeOptions } from "../util/index";
export default function initExtend(Vue) {
let cid = 0; //组件的唯一标识
// 创建子类继承Vue父类 便于属性扩展
Vue.extend = function (extendOptions) {
// 创建子类的构造函数 并且调用初始化方法
const Sub = function VueComponent(options) {
this._init(options); //调用Vue初始化方法
};
Sub.cid = cid++;
Sub.prototype = Object.create(this.prototype); // 子类原型指向父类
Sub.prototype.constructor = Sub; //constructor指向自己
Sub.options = mergeOptions(this.options, extendOptions); //合并自己的options和父类的options
return Sub;
};
}
В частности, см. этоРукописный исходный код Vue2.0 (8)-компонентный принцип
9 Могут ли методы маршрутизации pushState и replaceState в vue-router вызвать событие popSate?
ответ:не можем
pushState и replaceState
Новый интерфейс HTML5, вы можете изменить URL-адрес (есть междоменные ограничения) без обновления страницы, эта мощная функция позже использовалась в одностраничных приложениях, таких как: vue-router, react-router-dom.
Примечание: Только изменив URL-адрес, веб-страница на самом деле не будет переходить и не будет получать новый контент.По сути, веб-страница остается на исходной странице.
window.history.pushState(state, title, targetURL);
@状态对象:传给目标路由的信息,可为空
@页面标题:目前所有浏览器都不支持,填空字符串即可
@可选url:目标url,不会检查url是否存在,且不能跨域。如不传该项,即给当前url添加data
window.history.replaceState(state, title, targetURL);
@类似于pushState,但是会直接替换掉当前url,而不会在history中留下记录
Событие popstate запускается при нажатии кнопок «назад» и «вперед» (или при вызове методов history.back(), history.forward(), history.go())
Примечание: использование history.pushState() или history.replaceState() не вызовет событие popstate.
10 Что такое встряхивание деревьев и каков принцип?
Встряхивание дерева - этоОчистить лишний кодТехнология оптимизации объема упаковки проекта, технический термин — устранение мертвого кода.
качание деревапринципчто это такое?
ES6 Module引入进行静态分析,故而编译的时候正确判断到底加载了那些模块
静态分析程序流,判断那些模块和变量未被使用或者引用,进而删除对应代码
Расширения: разница между импортом модуля в common.js и es6?
CommonJS — это спецификация модуля, которая изначально применялась к Nodejs и стала спецификацией модуля Nodejs. JavaScript, работающий на стороне браузера, также не имеет аналогичной спецификации.До выхода ES6 интерфейс также реализовывал набор той же спецификации модулей (например, AMD) для управления интерфейсными модулями. Начиная с ES6, был введен новый набор спецификаций модуля ES6, который реализует функцию модуля на уровне языковых стандартов, и реализация довольно проста, и ожидается, что он станет общим модульным решением для браузеров и серверов. Но в настоящее время браузеры не очень совместимы с модулем ES6.Экспорт и импорт, которые мы обычно используем в Webpack, будут преобразованы Babel в спецификацию CommonJS. Основные отличия в использовании:
1. Вывод модуля CommonJS — это копия значения, а вывод модуля ES6 — ссылка на значение.
2. Модуль CommonJS загружается во время выполнения, а модуль ES6 является интерфейсом вывода во время компиляции (статическая компиляция).
3. CommonJs — это экспорт одного значения, модуль ES6 может экспортировать несколько
4. CommonJs — это динамическая грамматика, которая может быть написана на суждениях, а статическая грамматика модуля ES6 может быть написана только на верхнем уровне.
5. Текущий модуль this для CommonJs, а this для модуля ES6 не определен.
11 Что такое Вавилон, принцип ты понимаешь?
Babel — это компилятор JavaScript. Он компилирует последнюю версию javascript в версию, которую можно выполнить в данный момент.Короче говоря, использование babel позволяет нам свободно использовать этот новый и последний синтаксис es6 и даже es7 в текущем проекте.
Три основных этапа обработки Babel: анализ, преобразование и генерация.
-
Разобрать Разберите код в абстрактное синтаксическое дерево (AST), каждый движок js (например, движок V8 в браузере Chrome) имеет свой собственный синтаксический анализатор AST, а Babel реализуется через Babylon. В процессе синтаксического анализа есть две фазы: лексический анализ и синтаксический анализ.На этапе лексического анализа код в виде строки преобразуется в поток токенов, которые аналогичны узлам в AST, а на этапе синтаксического анализа преобразуется команда в поток токенов.Поток карт преобразуется в форму AST, и на этом этапе информация в токене будет преобразована в структуру представления AST.
-
конвертировать На этом этапе Babel берет AST и выполняет его обход в глубину с помощью babel-traverse, добавляя, обновляя и удаляя узлы в процессе. Эта часть также является частью, в которую вступает плагин Babel.
-
генерировать Преобразованный AST преобразуется в js-код с помощью babel-генератора Процесс заключается в том, чтобы сначала пройти весь AST в глубину, а затем создать строку, которая может представлять преобразованный код.
Если вы хотите узнать больше, вы можете увидеть[Практическая серия] Основа
12 Цепное суждение прототипа
Пожалуйста, напишите ответ ниже
Object.prototype.__proto__;
Function.prototype.__proto__;
Object.__proto__;
Object instanceof Function;
Function instanceof Object;
Function.prototype === Function.__proto__;
Object.prototype.__proto__; //null
Function.prototype.__proto__; //Object.prototype
Object.__proto__; //Function.prototype
Object instanceof Function; //true
Function instanceof Object; //true
Function.prototype === Function.__proto__; //true
В этом разделе подробно рассматриваются точки знаний, связанные с цепочкой прототипов, особенно отношения между функцией и объектом.
Настоятельно рекомендуется всем прочитать эту статью и после прочтения все станет ясноСерия прототипов JavaScript (3) Взаимосвязь и проблема яйца функции, объекта, нулевого значения и т. д.
13 Что такое РАФ и РИЦ
запросAnimationFrame:Скажите браузеру выполнить входящую функцию обратного вызова (обычно это функция, которая манипулирует dom и обновляет анимацию) перед следующей перерисовкой; поскольку она выполняется один раз за кадр, в результате количество выполнений в секунду совпадает с количество обновлений экрана браузера, обычно 60 раз в секунду.
запросIdleCallback:: будет выполнять обратные вызовы во время простоя браузера, что позволяет разработчикам выполнять низкоприоритетные задачи в основном цикле событий, не влияя на некоторые критичные к задержке события. Если обратных вызовов несколько, то они будут выполняться по принципу «первым пришел — первым обслужен», но при передаче таймаута, во избежание таймаута, порядок может быть нарушен.
В этой теме можно подробно задать вопрос о процессе рендеринга каждого кадра браузера.Подробности см. в этой статье.Подробное объяснение requestIdleCallback и requestAnimationFrame
трудность
1 Принцип реализации Es6 let
необработанный код es6
var funcs = [];
for (let i = 0; i < 10; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // 0
код es5, скомпилированный babel (polyfill)
var funcs = [];
var _loop = function _loop(i) {
funcs[i] = function () {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
funcs[0](); // 0
На самом деле, мы можем видеть из результатов компиляции babel, что let использует замыкания и области видимости для достижения эффекта блочной области видимости Результаты компиляции let различны в разных ситуациях.
2 Как спроектировать и реализовать механизм рендеринга
Этот вопрос является последним вопросом в конце байтаоткрытый вопросФиксированного ответа нет. Я чувствовал, что концепция вопроса слишком велика, и я был совершенно сбит с толку. Я просто ответил на принцип браузерного рендеринга. Похоже, что интервьюер не удовлетворен. Ха-ха Если вас просят разработать рендеринг двигатель, с чего начать?
Вы можете обратиться к статьеМеханизм рендеринга страницы в браузере, о котором вы не знаете
3 Каков конкретный принцип реализации require
требуют обоснования
требуется путь поиска
То, что делают require и module.exports, несложно. Давайте сначала предположим, что есть глобальный объект {}, который изначально пуст. Когда вам нужен файл, выньте файл и выполните его. Если файл существует в нем, модуль. exports, при запуске к этой строке кода добавьте к этому объекту значение module.exports, ключ — соответствующее имя файла, и в итоге этот объект будет выглядеть так:
{
"a.js": "hello world",
"b.js": function add(){},
"c.js": 2,
"d.js": { num: 2 }
}
当你再次 require 某个文件时,如果这个对象里面有对应的值,就直接返回给你,如果没有就重复前面的步骤,执行目标文件,然后将它的 module.exports 加入这个全局对象,并返回给调用者。 Этот глобальный объект на самом деле является кешем, о котором мы часто слышим.所以 require 和 module.exports 并没有什么黑魔法,就只是运行并获取目标文件的值,然后加入缓存,用的时候拿出来用就行。
В частности, см. этоУглубленный механизм загрузки модулей Node.js, рукописная функция запроса
4 Индикаторы позиционирования и оптимизации производительности внешнего интерфейса
Оптимизация производительности интерфейса ужеклишеМногие говорят о решениях по оптимизации производительности, но на самом деле мало знают об анализе производительности, позиционировании и показателях производительности, поэтому, хотя этот вопрос связан с производительностью, основное внимание уделяется тому, как выполнять обычные проекты.Таргетинг по эффективности и анализ
- Мы можем контролировать от передней производительности -Похороненныйтак же какwindow.performanceСвязанный API для ответа
- Также доступно в инструментах анализа производительности Производительность иLighthouse
- Также доступно изПредставлениеLCP FCP FID CLS подождите, чтобы начать
Ниже приведены статьи, связанные с производительностью, вы можете пойти и увидеть
Интерфейсный инструмент для мониторинга производительности за 5 минут
Индикаторы оптимизации производительности внешнего интерфейса + инструменты обнаружения
резюме
Сутры над лицом Брата Акулы служат только в качествеметание нефритаРоль внешнего интерфейса Различные вопросы интервью возникают в бесконечном потоке, мы просто помним, что ответа недостаточно В конце концов, я надеюсь, что вы узнаете принципы, лежащие в основе точек знаний внешнего интерфейса, через это интервью. из достаточного количества собеседований по социальному набору.Очень важно иметь прошлый проектный опыт иОсновные моменты и трудности проектаПокажите, что этот вопрос нельзя решить чисткой, или он должен полагаться на непрерывную практику каждого и накопление в обычной работе, и отказывайтесь быть инженером по резюме.Наконец, я желаю всем взолотая девятка серебряная десяткаВ хороший день я получу предложение, которым я доволен~
Ссылки на другие вопросы интервью
- Самые полные вопросы интервью Vue + подробные ответы
- Интервью с 6 крупными заводами за один день - предложение здесь
- Самые полные рукописные вопросы по программированию JS
Группа передовых рыболовных технологий Brother Shark
Приветствую всех на технических биржахСвязь