предисловие
Я проработал в Alibaba и Tencent 6 лет, а в качестве фронтенд-интервьюера — 3 года.Я собрал вопросы и ответы, которые часто задают мои коллеги и я, в своем интервью Weekly-FE-Interview на Github. Я надеюсь быть полезным.
Если вы столкнетесь с какими-либо вопросами, которые вы не понимаете во время интервью с летучими мышами, пожалуйста, пришлите мне вопрос Я обобщу темы и запишу пункты интервью и ответы в еженедельном журнале, чтобы все могли прогрессировать и расти вместе, и помочь каждому войти в себя.идеальный бизнес.
Адрес проекта:GitHub.com/Ай Руи спать/мы…
Подборка распространенных вопросов на собеседовании
Ниже приведены общие вопросы интервью десяти основных фабрик.Если вы понимаете и понимаете их все, вы можете получить 1-2 вопроса в одностороннем или телефонном интервью. Маленькие друзья не могут спешить увидеть ответ первым, сначала попробуйте подумать и осознать его самостоятельно, а потом посмотрите на ответ.
Вопрос 1: Что такое 499 в коде состояния http? Как появляется 499, как устранить неполадки и решить
499 соответствует «клиент закрыл соединение». Клиент запрашивает ожидание закрытия соединения. Скорее всего, это связано с тем, что время обработки на стороне сервера слишком велико, а клиент «нетерпеливо» ждет. Другая причина заключается в том, что 499 появится, если сообщение будет отправлено дважды слишком быстро. Решение:
- Внешний интерфейс устанавливает максимальное время ожидания тайм-аута, чтобы быть больше
- Настройте proxy_ignore_client_abort на nginx;
Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…
Вопрос 2: Как пройти по дереву домов
function traversal(node) {
//对node的处理
if (node && node.nodeType === 1) {
console.log(node.tagName);
}
var i = 0,
childNodes = node.childNodes,
item;
for (; i < childNodes.length; i++) {
item = childNodes[i];
if (item.nodeType === 1) {
//递归先序遍历子节点
traversal(item);
}
}
}
Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…
Вопрос 3: Что делает новый оператор
Четыре шага:
1. Создайте пустой объект, и переменная this ссылается на объект, // lat target = {};
2. Наследовать прототип функции. // цель.proto = func.prototype;
3. К объекту, на который ссылается this, добавляются свойства и методы. и выполнил функцию func// func.call(target);
4. На вновь созданный объект ссылается this и, наконец, неявно возвращает this. // Если res, возвращаемый func.call(target), является объектом или функцией, возвращаем его
function new(func) {
lat target = {};
target.__proto__ = func.prototype;
let res = func.call(target);
if (typeof(res) == "object" || typeof(res) == "function") {
return res;
}
return target;
}
Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…
Вопрос 4: Рукописный код, простая реализация вызова
Function.prototype.call2 = function(context) {
var context = context || window; //因为传进来的context有可能是null
context.fn = this;
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push("arguments[" + i + "]"); //不这么做的话 字符串的引号会被自动去掉 变成了变量 导致报错
}
args = args.join(",");
var result = eval("context.fn(" + args + ")"); //相当于执行了context.fn(arguments[1], arguments[2]);
delete context.fn;
return result; //因为有可能this函数会有返回值return
}
Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…
Вопрос 5: Рукописный код, простая реализация apply
Function.prototype.apply2 = function(context, arr) {
var context = context || window; //因为传进来的context有可能是null
context.fn = this;
var args = [];
var params = arr || [];
for (var i = 0; i < params.length; i++) {
args.push("params[" + i + "]"); //不这么做的话 字符串的引号会被自动去掉 变成了变量 导致报错
}
args = args.join(",");
var result = eval("context.fn(" + args + ")"); //相当于执行了context.fn(arguments[1], arguments[2]);
delete context.fn;
return result; //因为有可能this函数会有返回值return
}
Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…
Вопрос 6: Рукописный код, простая реализация bind
Function.prototype.bind2 = function(context) {
var _this = this;
var argsParent = Array.prototype.slice.call(arguments, 1);
return function() {
var args = argsParent.concat(Array.prototype.slice.call(arguments)); //转化成数组
_this.apply(context, args);
};
}
Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…
Вопрос 7: Объясните, как работает HTTPS
HTTPS требует рукопожатия между клиентом (браузером) и сервером (веб-сайтом) перед передачей данных. Протокол TLS/SSL — это не только набор зашифрованных протоколов передачи, но и произведение искусства, тщательно разработанное художником.В TLS/SSL используются асимметричное шифрование, симметричное шифрование и алгоритмы HASH. Краткое описание процесса рукопожатия выглядит следующим образом:
-
Браузер отправляет набор поддерживаемых им правил шифрования на веб-сайт.
-
Веб-сайт выбирает набор алгоритмов шифрования и алгоритмов HASH и отправляет свою идентификационную информацию обратно в браузер в виде сертификата. Сертификат содержит такую информацию, как адрес веб-сайта, открытый ключ шифрования и орган, выдавший сертификат.
-
После получения сертификата веб-сайта браузер должен сделать следующее:
-
а) Проверить легитимность сертификата (является ли организация, выпустившая сертификат, законной, совпадает ли адрес веб-сайта, содержащийся в сертификате, с посещаемым адресом и т. д.), если сертификат является доверенным, небольшая блокировка будет отображаться в строке браузера, иначе будет сообщение о том, что сертификат не является доверенным.
-
Если сертификат является доверенным или если пользователь принимает ненадежный сертификат, браузер генерирует случайный пароль и шифрует его с помощью открытого ключа, указанного в сертификате.
-
Используйте согласованный HASH для расчета сообщения рукопожатия, зашифруйте сообщение сгенерированным случайным числом и, наконец, отправьте всю ранее сгенерированную информацию на веб-сайт.
-
-
После того, как веб-сайт получает данные, отправленные браузером, он делает следующее:
-
а) Используйте свой собственный закрытый ключ для расшифровки информации и извлечения пароля, используйте пароль для расшифровки сообщения рукопожатия, отправленного браузером, и проверьте, соответствует ли HASH тому, который отправлен браузером.
-
б) Зашифровать сообщение рукопожатия паролем и отправить его в браузер.
-
-
Браузер расшифровывает и вычисляет HASH сообщения рукопожатия.Если он согласуется с HASH, отправленным сервером, процесс рукопожатия на этом заканчивается, и все данные связи после этого будут зашифрованы случайным паролем, сгенерированным браузером. и с использованием алгоритма симметричного шифрования.
Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…
Вопрос 8: Расскажите о симметричном шифровании https и асимметричном шифровании.
Симметричное шифрование: Отправитель и получатель должны иметь один и тот же ключ, который используется как для отправки, так и для получения сообщений. По сравнению с асимметричным шифрованием, симметричное шифрование имеет более высокую скорость шифрования и дешифрования, но обе стороны должны знать ключ заранее, а ключ может быть украден в процессе передачи, поэтому безопасность не так высока, как у асимметричного шифрования.
Асимметричное шифрование: Перед отправкой сообщения получатель должен заранее сгенерировать открытый ключ и закрытый ключ, а затем отправить открытый ключ отправителю. После получения открытого ключа отправитель шифрует отправляемые данные с помощью открытого ключа и отправляет их получателю. Получив полученные данные, расшифруйте их закрытым ключом. В этом процессе открытый ключ отвечает за шифрование, а закрытый — за расшифровку, и даже если данные будут перехвачены при передаче, злоумышленник не сможет их взломать, поскольку у него нет закрытого ключа. Скорость шифрования и дешифрования алгоритма асимметричного шифрования ниже, чем у алгоритма симметричного шифрования, но безопасность выше.
Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…
Вопрос 9: Простая реализация загрузки кода проекта по запросу, например import {Button} из 'antd', при упаковке упаковывается только кнопка
Принцип прост, т.
import { Select, Pagination, Button } from 'xxx-ui';
Преобразовано в Babel
import Button from `xxx-ui/src/components/ui-base/Button/Button`;
import Pagination from `xxx-ui/src/components/ui-base/Pagination/Pagination`;
import Select from `xxx-ui/src/components/ui-base/Select/Select`;
Настройте и расширьте плагин Babel, код выглядит следующим образом:
visitor: {
ImportDeclaration (path, { opts }) {
const specifiers = path.node.specifiers;
const source = path.node.source;
// 判断传入的配置参数是否是数组形式
if (Array.isArray(opts)) {
opts.forEach(opt => {
assert(opt.libraryName, 'libraryName should be provided');
});
if (!opts.find(opt => opt.libraryName === source.value)) return;
} else {
assert(opts.libraryName, 'libraryName should be provided');
if (opts.libraryName !== source.value) return;
}
const opt = Array.isArray(opts) ? opts.find(opt => opt.libraryName === source.value) : opts;
opt.camel2UnderlineComponentName = typeof opt.camel2UnderlineComponentName === 'undefined'
? false
: opt.camel2UnderlineComponentName;
opt.camel2DashComponentName = typeof opt.camel2DashComponentName === 'undefined'
? false
: opt.camel2DashComponentName;
if (!types.isImportDefaultSpecifier(specifiers[0]) && !types.isImportNamespaceSpecifier(specifiers[0])) {
// 遍历specifiers生成转换后的ImportDeclaration节点数组
const declarations = specifiers.map((specifier) => {
// 转换组件名称
const transformedSourceName = opt.camel2UnderlineComponentName
? camel2Underline(specifier.imported.name)
: opt.camel2DashComponentName
? camel2Dash(specifier.imported.name)
: specifier.imported.name;
// 利用自定义的customSourceFunc生成绝对路径,然后创建新的ImportDeclaration节点
return types.ImportDeclaration([types.ImportDefaultSpecifier(specifier.local)],
types.StringLiteral(opt.customSourceFunc(transformedSourceName)));
});
// 将当前节点替换成新建的ImportDeclaration节点组
path.replaceWithMultiple(declarations);
}
}
}
Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…
Вопрос 10: Простая рукописная реализация обещаний
// 简易版本的promise
// 第一步: 列出三大块 this.then resolve/reject fn(resolve,reject)
// 第二步: this.then负责注册所有的函数 resolve/reject负责执行所有的函数
// 第三步: 在resolve/reject里面要加上setTimeout 防止还没进行then注册 就直接执行resolve了
// 第四步: resolve/reject里面要返回this 这样就可以链式调用了
// 第五步: 三个状态的管理 pending fulfilled rejected
// *****promise的链式调用 在then里面return一个promise 这样才能then里面加上异步函数
// 加上了catch
function PromiseM(fn) {
var value = null;
var callbacks = [];
//加入状态 为了解决在Promise异步操作成功之后调用的then注册的回调不会执行的问题
var state = 'pending';
var _this = this;
//注册所有的回调函数
this.then = function (fulfilled, rejected) {
//如果想链式promise 那就要在这边return一个new Promise
return new PromiseM(function (resolv, rejec) {
//异常处理
try {
if (state == 'pending') {
callbacks.push(fulfilled);
//实现链式调用
return;
}
if (state == 'fulfilled') {
var data = fulfilled(value);
//为了能让两个promise连接起来
resolv(data);
return;
}
if (state == 'rejected') {
var data = rejected(value);
//为了能让两个promise连接起来
resolv(data);
return;
}
} catch (e) {
_this.catch(e);
}
});
}
//执行所有的回调函数
function resolve(valueNew) {
value = valueNew;
state = 'fulfilled';
execute();
}
//执行所有的回调函数
function reject(valueNew) {
value = valueNew;
state = 'rejected';
execute();
}
function execute() {
//加入延时机制 防止promise里面有同步函数 导致resolve先执行 then还没注册上函数
setTimeout(function () {
callbacks.forEach(function (cb) {
value = cb(value);
});
}, 0);
}
this.catch = function (e) {
console.log(JSON.stringify(e));
}
//经典 实现异步回调
fn(resolve, reject);
}
Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…
Эпилог
Я также написал несколько статей о передовых знаниях в области интерфейса.Если вы считаете, что это хорошо, вы можете нажать звездочку.
Адрес проекта блога:GitHub.com/Эрик сонный/был бы…
Я Маленький Головастик, старший фронтенд-инженер в Tencent, и каждую неделю я буду преодолевать вместе со мной несколько технических трудностей. Я надеюсь, что это поможет вам на пути к развитию ваших друзей и поможет вам войти в ваше идеальное предприятие.