올해 취업 상황은 그야말로 암울합니다. 내년은 올해보다 더 안 좋을 것이라는 '운이 좋은 마음'으로 한달 반 동안 고민한 끝에 꽤 좋은 제안을 받았습니다. , 급여 및 플랫폼이 크게 개선되었지만 여전히 내 심리적 기대와는 큰 격차가 있습니다. 그래서 가장 큰 결론은: 노골적으로 말하지 마세요! 알몸으로 아무 말도 하지 마세요! 알몸으로 아무 말도 하지 마세요! 인터뷰를 하면서 받는 압박감과 현실과 이상의 괴리로 인한 심리적 피해는 헤아릴 수 없을 만큼 크기 때문에 그런 환경에서 살아남는 것이 좋은 선택이다.
관련 추천: 2023년 대규모 프론트엔드 면접 질문 요약(모음)
다음은 일반적인 상황에서 프론트엔드 인터뷰에서 경험하게 될 다음 4단계와 3가지 결정 요소를 요약한 것입니다.
프론트엔드 직원으로서는 기술의 깊이와 폭이 1위입니다. 이때 자신의 위치와 방향을 찾아야 합니다.
둘째, 좋은 의사소통 능력과 표현력, 의상과 퍼포먼스, 기타 오프사이트 요소는 면접관의 인지도를 높일 수 있습니다.
어떤 사람들은 매우 능숙하지만 면접관은 당신이 오만하고 엉성하며 독선적이며 명확하게 표현하지 못한다고 생각하여 당신을 거부할 것입니다.
다음은 제가 받은 질문과 제가 준비한 전체 내용을 요약한 것입니다. 왜냐하면 면접 과정에서 면접관과의 의사소통은 대체로 단순한 승인이 아니기 때문에 자신의 지식을 전달하는 것이 가장 좋습니다. 요약하고 간결하게 표현한 후, 면접관의 질문에 따라 즉석에서 완성합니다. [추천 학습: 웹 프론트 엔드, 프로그래밍 교육]
면접관은 자기 소개를 요구하며, 자기 소개의 범위를 제한하지 않습니다. 자기소개서에서 배우기 나는 당신을 알고 있으므로 소개는 짧고 원활해야 합니다. 다른 면접관을 만나도 자기소개서의 내용은 똑같을 수 있으므로 미리 단어를 준비하고 확실하게 하는 것이 중요합니다. 주의를 기울이십시오: 넘어지지 말고 자신감을 가지십시오! 원활한 표현력과 소통 능력도 면접관이 지원자를 평가하는 포인트 중 하나입니다. 나도 면접관이었는데, 자신감 있고 관대한 지원자가 선호될 가능성이 더 높습니다.
1. 기본 이력서를 포함한 개인 소개(기본 정보)는 짧아야 합니다
2. 기술적인 것과 비기술적인 것을 포함하여 자신이 잘하는 것. 기술적인 사람들은 당신의 전환을 이해할 수 있고, 기술적인 사람이 아닌 사람들은 당신을 사람으로 이해할 수 있습니다
3. 당신이 수행한 가장 핵심적인 프로젝트를 선택하고, 추천과 같은 모든 프로젝트를 소개하지 마십시오
4. 관심사나 의견, 심지어 자신의 경력 계획까지. 이것은 면접관에게 느낌을 주어야 합니다: "던지기" 또는 "생각"에 열심입니다
예:
안녕하세요 면접관님, 제 이름은 xx년에 xx대학교를 졸업했고 졸업 후 프론트엔드 개발에 종사해 왔습니다. . 일하다.
제가 잘하는 기술 스택은 vue family bucket입니다. 저는 vue2와 vue3의 사용 및 소스 코드에 대해 어느 정도 연구했습니다. 저는 webpack 및 vite 구현을 주도한 경험이 있습니다. 중대형 프로젝트를 처음부터 끝까지 수행할 수 있습니다.
이전 회사에서는 주로 xx 제품군을 담당했고, 주요 업무는 다음과 같았습니다. . . . . .
개발 관련 업무 외에도 그는 요구 사항 검토, UI/UE 상호 작용 검토 심사위원, 개발 일정 담당, 멤버 협업, 멤버 코드 검토, 정기 회의 구성 등 특정 기술 관리 경험도 보유하고 있습니다.
보통 제가 만든 블로그에 연구 기사나 연구 노트를 기록하고 있으며 독창적인 기술 기사를 작성하여 Nuggets에 게시하고 있으며 XX상을 수상했습니다.
일반적으로 자기소개는 3~5분 정도를 유지하도록 노력하세요. 간결하고 핵심을 전달하는 것이 가장 중요하며, 그다음에는 자신의 능력과 장점을 강조하세요.
일반 기술 면접관의 경우 자기 소개는 면접 전 관례적인 서두에 불과합니다. 일반적으로 이력서에 기재된 기본 정보는 이미 귀하에 대한 기본적인 이해를 충족시켰습니다. 그러나 감독자 수준의 면접관이나 HR의 경우, 그들은 귀하의 성격, 행동 습관, 스트레스 저항성 및 기타 포괄적인 능력을 중요하게 여길 것입니다. 따라서 면접 과정에서 최대한 긍정적이어야 하며, 지속적인 학습, 팀워크 등 폭넓은 취미를 가지고 있어야 하며, 무조건 야근을 할 수 있어야 합니다. 물론 치트를 허용하려는 것은 아니지만, 이런 환경에서는 이러한 '사이드 능력'도 어느 정도 경쟁력을 높일 수 있는 마법 무기이기도 하다.
현재 시장 상황에서 면접 통지를 받은 경우에는 귀하의 프로젝트 경험이 귀하가 모집하는 직위에 더 적합하기 때문일 가능성이 높습니다. 따라서 다음과 같이 프로젝트 준비에 특별한 주의를 기울여야 합니다.
프로젝트에 사용된 기술을 자세히 알아보세요
디자인 전반의 통제프로젝트 아이디어
프로젝트 관리운영 프로세스
팀워크 능력
.프로젝트의 최적화 포인트
는 무엇인가요2. 저는 주로 Vue의 소스 코드를 계속해서 배우고 있으며, 예전에 한줄 한줄 썼었는데 teleport
소스코드를 집중적으로 읽어보고, 작성하는데 30시간 정도 걸렸고, 소스코드 각 줄의 기능과 역할을 해석해봤습니다(그런데 읽기와 좋아요가 왜 이렇게 적나요) .제 개인적인 계획은 다음과 같습니다.
사람마다 다르기 때문에 그에 맞게 준비하세요. 다양한 규모의 팀의 R&D 모델은 매우 다르기 때문입니다.
코드 검토의 목표2. 확장성: 캡슐화 기능(구성 요소 및 코드 논리 여부) 애플리케이션 재현 가능, 확장성)
5. 알고리즘을 사용하여 더 우아하고 성능이 뛰어난 코드를 작성하는 방법
팀을 이끄는 방법저는 이전 회사에서 기술 관리 직책을 맡았습니다.
0,
개발 사양 구현: 각 사람이 단독으로 제품 개발을 담당하고 그 다음에는 일반적으로 지정합니다. 소수의 사람들이 공개 모듈을 개발합니다
2. 코드 품질 보증: 우리는 매주 코드를 검토하고 코드에 대한 교차 검토를 구성하며 수정 결과의 출력 기사를 위키에 올릴 것입니다.
3 정기 회의 조직: 매주 정기 회의를 조직하여 각자의 진행 상황과 위험을 동기화하고 각자의 진행 상황에 따라 업무를 할당합니다.
4. 기술 공유: 가끔 기술 공유도 진행합니다. 처음에는 마이크로 프론트 엔드 시스템, ice stark
5의 소스 코드, Public Demand Pool 등을 공유했습니다. webpack5/vite의 업그레이드 등; pnpm 사용 소개, 토폴로지 맵 성능 최적화
6, 최적화 프로젝트: 제품의 첫 번째 버전이 나온 후 특별한 성능 최적화 프로젝트, 첫 번째 화면 로딩 성능, 패키징 볼륨 최적화도 시작했습니다. ; 해당 최적화 항목은 모두가 책임지도록 하세요
잔업을 하는 경우에는 일반적으로 두 가지 상황이 있다고 생각합니다.
첫째, 프로젝트 일정이 빡빡해서 당연히 프로젝트 진행이 우선이고, 결국 모두가 이것에 생계가 달려있습니다
둘째, 자신의 능력 문제, 사업에 익숙하지 않거나 새로운 기술 스택을 도입하면 따라잡기 위해 야근을 해야 할 뿐만 아니라, 여가 시간을 활용하여 부족한 점을 보완하고 공부해야 한다고 생각합니다
저는 주로 독서를 좋아합니다. 즉, WeChat 읽기에서 심리학, 시간 관리, 말하기 기술에 관한 책을 읽습니다.
그런 다음 기사를 씁니다. 왜냐하면 메모하는 것만으로는 잊어버리기 쉽기 때문입니다. 나는 다른 사람의 내용만 기록하고 나만의 독창적인 기사를 작성하는 과정에서 매우 높은 비율의 지식을 내 것으로 변환할 수 있습니다. 따라서 나만의 금광 기사 외에도 종종 금광 기사에 대한 의견도 있습니다. 기사는 위키로 내보내집니다.
다른 취미는 친구들과 농구하고 노래하는 것입니다.
기술 인터뷰에 주의하세요. 간결하고 요점을 명확하게 하세요. 적절하게 자세하게 설명해주시고, 이해가 안 되시면 이해가 안 된다고 말씀해주세요. 면접 과정은 면접관과의 대면 소통 과정이기 때문에 면접관은 핵심 내용을 말하지 않고 오랫동안 수다를 떠는 지원자를 좋아하지 않을 것이다. 동시에, 말하는 과정에서 듣는 사람은 수동적으로 반응할 것이다. 관심 없는 부분은 무시하기 때문에 특정 기술의 핵심 기능을 부각시키고 핵심을 중심으로 적절하게 확장하는 것이 필요합니다.
대기업은 기본적으로 알고리즘 질문을 통해 후보자를 선별합니다. 알고리즘에는 지름길이 없습니다. 차근차근 질문에 답한 뒤 다시 질문에 답하는 것뿐입니다.
기술 면접 과정은 주로 프론트엔드 분야와 관련된 기술에 대한 질문을 하게 됩니다. 일반적으로 면접관은 귀하의 소속을 기반으로 진행되며, 더 자주 면접관은 이전에 준비한 면접 질문을 기반으로 하거나, 프로젝트 팀이 잘 알고 있는 기술이기 때문에 질문하려면 클릭하세요. 모든 측면이 상당히 까다롭기 때문입니다.
발전 전망이 좋은 중견 기업에 입사하고 싶다면, 다른 사람의 경험만 외운다고 자신을 속일 수는 없습니다. 포인트는 종합적인 학습을 거쳐 추출한 핵심 지식 포인트 중 일부이므로 면접관의 '다양한 사고'를 두려워하지 않습니다.
면접 과정에는 일반적으로 다음 8가지 주요 지식 유형을 고려하는 과정이 포함됩니다:
JS/CSS/TypeScript/프레임워크(Vue, React)/브라우저 및 네트워크/성능 최적화/프론트엔드 엔지니어링/아키텍처/기타
따라서 인터뷰 전 기술적인 준비는 결코 하루아침에 이루어지지 않습니다. 또한 매일의 축적이 필요합니다. 예를 들어, 장기적으로는 작은 지식 포인트 중 하나를 종합적으로 공부하는 데 10~20분을 투자할 수 있습니다. 몇 년의 인터뷰라도 설득력있게 이야기하는 것만으로도 충분합니다 .
JS 학습용 빨간 봉투 책과 Yu Yu 씨의 심층 JS 시리즈 블로그기본적으로 괜찮습니다.
일반적인 JS 면접 질문에는 일반적으로 다음이 포함됩니다. 프로토타입 체인?
프로토타입의 본질은
객체이 프로토타입 객체는 생성자를 통해 생성된 인스턴스 객체에 대한 공유 속성을 제공하는 데 사용됩니다. 즉, 프로토타입 기반 상속 및 속성 공유를 구현하는 데 사용됩니다.
prototype
따라서 생성자를 통해 생성된 인스턴스 객체
는 모두 이 함수의 프로토타입 객체는 위의 속성을 상속받습니다 인스턴스의 속성을 읽을 때 찾을 수 없으면 객체와 관련된 프로토타입에서 속성을 찾습니다. 찾을 수 없으면 최상위 수준에 도달할 때까지 프로토타입의 프로토타입을 찾습니다. (최상위 수준은 所以通过原型一层层相互关联的链状结构就称为原型链。 定义:闭包是指引用了其他函数作用域中变量的函数,通常是在嵌套函数中实现的。 从技术角度上所有 js 函数都是闭包。 从实践角度来看,满足以下俩个条件的函数算闭包 即使创建它的上下文被销毁了,它依然存在。(比如从父函数中返回) 在代码中引用了自由变量(在函数中使用的既不是函数参数也不是函数局部变量的变量称作自由变量) 使用场景: 创建私有变量 vue 中的data,需要是一个闭包,保证每个data中数据唯一,避免多次引用该组件造成的data共享 延长变量的生命周期 一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的 应用 在绝大多数情况下,函数的调用方式决定了 1、全局的this非严格模式指向window对象,严格模式指向 undefined 2、对象的属性方法中的this 指向对象本身 3、apply、call、bind 可以变更 this 指向为第一个传参 4、箭头函数中的this指向它的父级作用域,它自身不存在 this js 代码执行过程中,会创建对应的执行上下文并压入执行上下文栈中。 如果遇到异步任务就会将任务挂起,交给其他线程去处理异步任务,当异步任务处理完后,会将回调结果加入事件队列中。 当执行栈中所有任务执行完毕后,就是主线程处于闲置状态时,才会从事件队列中取出排在首位的事件回调结果,并把这个回调加入执行栈中然后执行其中的代码,如此反复,这个过程就被称为事件循环。 事件队列分为了宏任务队列和微任务队列,在当前执行栈为空时,主线程回先查看微任务队列是否有事件存在,存在则依次执行微任务队列中的事件回调,直至微任务队列为空;不存在再去宏任务队列中处理。 常见的宏任务有 常见的微任务有 프로토타입을 통해 층층이 서로 연결되는 체인형 구조를 프로토타입 체인이라고 합니다. Object.prototype의 프로토타입
이고 값은 null입니다.) Object.prototype
的原型,值为null)。什么是闭包?
this 的指向
this
的值(运行时绑定)浏览器的事件循环?
setTimeout()
、setInterval()
、setImmediate()
、I/O、用户交互操作,UI渲染promise.then()
、promise.catch()
、new MutationObserver
、process.nextTick()
정의: 클로저는 일반적으로 중첩된 함수에서 구현되는 다른 함수 범위의 변수를 참조하는 함수
를 나타냅니다.사용 시나리오:
vue의 데이터는 각 데이터의 데이터가 고유함을 보장하고 구성 요소에 대한 여러 참조로 인해 발생하는 데이터 공유를 방지하기 위해 클로저여야 합니다.
변수의 수명 주기 연장
🎜일반적으로 함수가 반환된 후 함수의 어휘 환경이 파괴되지만, 클로저는 함수가 생성된 실행 컨텍스트가 파괴되더라도 해당 함수가 생성된 어휘 환경에 대한 참조를 저장합니다. 확장을 달성하기 위해 여전히 존재합니다. id="heading-17">🎜this 🎜🎜🎜를 가리키는 경우 대부분의 경우 함수를 호출하는 방법에 따라this
(런타임 바인딩) 🎜🎜1의 값이 결정됩니다. 엄격 모드는 창 개체를 가리키고, 엄격 모드는 정의되지 않은 창 개체를 가리킵니다🎜🎜2. 개체의 속성 메서드에서 이는 개체 자체를 가리킵니다🎜🎜3. 첫 번째 전달된 매개변수🎜🎜4. 화살표 함수의 이 매개변수는 자체적으로 존재하지 않는 상위 범위를 가리킵니다.🎜setTimeout()
, setInterval()
, setImmediate()
, I/O, 사용자 상호 작용 작업, UI가 포함됩니다. 렌더링🎜🎜🎜일반적인 마이크로 작업에는🎜promise.then()
, promise.catch()
, new MutationObserver
, process.nextTick이 포함됩니다. ()
🎜🎜🎜매크로 작업과 마이크로 작업의 근본적인 차이점🎜🎜🎜🎜🎜매크로 작업에는 실행과 콜백이 필요한 명확한 비동기 작업이 있으며 다른 비동기 스레드의 지원이 필요합니다🎜🎜🎜🎜마이크로 작업 명확하지 않습니다. 비동기 작업을 실행해야 하며 콜백만 필요하며 다른 비동기 스레드 지원은 필요하지 않습니다. 🎜🎜🎜🎜🎜JavaScript에서 데이터가 스택과 힙에 저장되는 방식🎜🎜🎜1. 기본 데이터 유형은 크기가 고정되어 있고 조작하기 쉽기 때문에 참조 크기에 저장됩니다. 데이터의 종류가 불확실하므로 스택에 저장하고 메모리 신청 시 크기를 결정하도록 합니다. 🎜🎜3. 이런 방식으로 별도로 저장하면 메모리 사용량을 최소화할 수 있습니다. 스택의 효율성은 힙의 효율성보다 높습니다🎜🎜4. 스택 메모리의 변수는 실행 환경이 종료된 후 즉시 가비지 수집되며, 힙 메모리의 변수에 대한 모든 참조는 종료되기 전에 종료되어야 합니다. 재활용되세요🎜🎜🎜v8 가비지 수집에 대해 이야기해 보겠습니다🎜🎜 🎜1. 객체의 생존 시간에 따라 여러 세대로 메모리 가비지 수집을 수행한 다음 세대마다 다른 재활용 알고리즘을 사용합니다. 시간에 대한 공간 청소 알고리즘을 사용합니다. 전체 공간을 두 개의 블록으로 나누고 그 중 하나의 변수만 존재하며, 살아남은 변수는 다른 공간으로 복사되고, 살아남지 않는 변수는 재활용됩니다. 반복해서 반복됩니다🎜🎜3. 이전 세대는 마크 지우기 및 마크 정렬을 사용합니다. 마크 지우기: 모든 객체를 순회하면 해당 객체에 액세스할 수 있으며(라이브), 라이브가 아닌 객체는 가비지로 재활용됩니다. 재활용 후에는 메모리 단절을 피하기 위해 살아있는 객체를 표시 및 정렬을 통해 메모리의 한쪽 끝으로 이동한 다음 이동이 완료된 후 경계 메모리를 정리해야 합니다🎜1. 일반 함수
는 ()
를 직접 사용하여 다음과 같은 매개변수를 호출하고 전달합니다. function test(x, y) { return x + y}
, test(3, 4)
function
直接使用()
调用并传参,如:function test(x, y) { return x + y}
,test(3, 4)
2、作为对象的一个属性方法调用,如:const obj = { test: function (val) { return val } }
, obj.test(2)
3、使用call
或apply
调用,更改函数 this 指向,也就是更改函数的执行上下文
4、new
可以间接调用构造函数生成对象实例
一般情况下,当执行到 script 标签时会进行下载 + 执行两步操作,这两步会阻塞 HTML 的解析;
async 和 defer 能将script的下载阶段变成异步执行(和 html解析同步进行);
async下载完成后会立即执行js,此时会阻塞HTML解析;
defer会等全部HTML解析完成且在DOMContentLoaded 事件之前执行。
DOM 事件流三阶段:
捕获阶段:事件最开始由不太具体的节点最早接受事件, 而最具体的节点(触发节点)最后接受事件。为了让事件到达最终目标之前拦截事件。
比如点击一个div,则 click 事件会按这种顺序触发: document => =>
=>
<div>,即由 document 捕获后沿着 DOM 树依次向下传播,<strong>并在各节点上触发捕获事件</strong>,直到到达实际目标元素。<li>
<p><strong>目标阶段</strong></p>
<p>当事件到达目标节点的,事件就进入了目标阶段。<strong>事件在目标节点上被触发</strong>(执行事件对应的函数),然后会逆向回流,直到传播至最外层的文档节点。</p>
</li>
<li>
<p><strong>冒泡阶段</strong></p>
<p>事件在目标元素上触发后,会继续随着 DOM 树一层层往上冒泡,直到到达最外层的根节点。</p>
</li>
<p>所有事件都要经历捕获阶段和目标阶段,但有些事件会跳过冒泡阶段,比如元素获得焦点 focus 和失去焦点 blur 不会冒泡</p>
<p><strong>扩展一</strong></p>
<p>e.target 和 e.currentTarget 区别?</p>
<ul>
<li>
<code>e.target
指向触发事件监听的对象。
e.currentTarget
指向添加监听事件的对象。例如:
<ul> <li><span>hello 1</span></li> </ul> let ul = document.querySelectorAll('ul')[0] let aLi = document.querySelectorAll('li') ul.addEventListener('click',function(e){ let oLi1 = e.target let oLi2 = e.currentTarget console.log(oLi1) // 被点击的li console.log(oLi2) // ul console.og(oLi1===oLi2) // false })
给 ul 绑定了事件,点击其中 li 的时候,target 就是被点击的 li, currentTarget 就是被绑定事件的 ul
事件冒泡阶段(上述例子),e.currenttarget
和e.target
是不相等的,但是在事件的目标阶段,e.currenttarget
和e.target
是相等的
作用:
e.target
可以用来实现事件委托,该原理是通过事件冒泡(或者事件捕获)给父元素添加事件监听,e.target指向引发触发事件的元素
扩展二
addEventListener 参数
语法:
addEventListener(type, listener); addEventListener(type, listener, options || useCapture);
type: 监听事件的类型,如:'click'/'scroll'/'focus'
listener: 必须是一个实现了 EventListener
接口的对象,或者是一个函数。当监听的事件类型被触发时,会执行
options:指定 listerner 有关的可选参数对象
preventDefault()
AbortSignal
,当它的abort()
const obj = { test: function (val) { return val } }
, obj.test(2)
call
또는 apply
를 사용하여 호출하세요. 그리고 this가 가리키는 함수를 변경합니다. 즉, 함수의 실행 컨텍스트를 변경하면4. new
는 간접적으로 생성자를 호출하여 객체 인스턴스
<html>
=> > => < code>e.target
은 이벤트 수신을 트리거하는 객체를 가리킵니다. 🎜🎜e.currentTarget
은 이벤트를 수신하기 위해 추가된 개체를 가리킵니다. 🎜🎜🎜예: 🎜// 比如 <input v-model="sth" /> // 等价于 <input :value="sth" @input="sth = $event.target.value" />
e.target
은 동일하지 않지만 이벤트의 대상 단계에서는 e.currenttarget
및 e.target
>같음 🎜🎜함수: 🎜🎜e.target
을 사용하여 이벤트 위임, 원칙은 이벤트 버블링(또는 이벤트 캡처) 상위 요소를 수신하는 이벤트를 추가하려면 e.target이 트리거 이벤트를 트리거한 요소를 가리킵니다. 🎜🎜🎜Extension 2🎜🎜🎜addEventListener 매개변수🎜🎜구문: 🎜// 父组件 <my-button v-model="number"></my-button> // 子组件 <script> export default { props: { value: Number, // 属性名必须是 value }, methods: { add() { this.$emit('input', this.value + 1) // 事件名必须是 input }, } } </script>
저자는 주로 Vue 관련 개발에 종사하고 있으며, React 관련 프로젝트도 해본 적이 있습니다. 물론 React는 프로젝트를 할 수 있는 수준에 불과하니 그런 편입니다. Vue 소스 코드 시리즈를 배우면 프레임워크가 비싸지 않습니다. 학습 과정에서도 마찬가지입니다. 프레임워크의 원리를 마스터할 수 있다면 다른 프레임워크를 배우는 것은 시간 문제일 뿐입니다.
1. 데이터 가변성
setState
를 통해서만 전달될 수 있는 함수형 프로그래밍, 불변 데이터 및 단방향 데이터 흐름을 옹호합니다. 또는 < code>onchange를 사용하여 뷰 업데이트를 구현합니다setState
或者onchange
来实现视图更新2、写法
3、diff 算法
react
主要使用diff队列保存需要更新哪些DOM,得到patch树,再统一操作批量更新DOM。,需要使用shouldComponentUpdate()
来手动优化react的渲染。扩展:了解 react hooks吗
组件类的写法很重,层级一多很难维护。
函数组件是纯函数,不能包含状态,也不支持生命周期方法,因此无法取代类。
React Hooks 的设计目的,就是加强版函数组件,完全不使用"类",就能写出一个全功能的组件
React Hooks 的意思是,组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。
Vue 在处理更新同类型 vnode 的一组子节点(比如v-for渲染的列表节点)的过程中,为了减少 DOM 频繁创建和销毁的性能开销:
对没有 key 的子节点数组更新是通过就地更新的策略。它会通过对比新旧子节点数组的长度,先以比较短的那部分长度为基准,将新子节点的那一部分直接 patch 上去。然后再判断,如果是新子节点数组的长度更长,就直接将新子节点数组剩余部分挂载;如果是新子节点数组更短,就把旧子节点多出来的那部分给卸载掉)。所以如果子节点是组件或者有状态的 DOM 元素,原有的状态会保留,就会出现渲染不正确的问题。
有 key 的子节点更新是调用的patchKeyedChildren
Vue는 데이터 가변성을 기반으로 반응형 데이터를 설계하고 데이터 변경을 모니터링하여 자동으로 뷰를 업데이트합니다
2. 작성 방법
🎜🎜React는 jsx + 인라인 스타일 사용을 권장합니다. 양식은 모두 js에 있습니다🎜🎜Vue는 구성 요소 내에서 모듈(tmplate/script/style)로 구분된 단일 파일 구성 요소(SFC) 형식입니다. 물론 vue는 vue의 UI를 개발할 때 사용할 수 있는 jsx 형식도 지원합니다. 컴포넌트 라이브러리🎜 🎜🎜3. Diff 알고리즘🎜🎜🎜Vue2는 이중 비교를 사용하고, Vue3은 빠른 비교를 사용합니다.🎜🎜react
는 주로 diff 대기열을 사용하여 업데이트해야 하는 DOM을 저장하고 패치를 가져옵니다. 그런 다음 통합 작업을 수행하여 DOM을 일괄적으로 업데이트합니다. , 반응 렌더링을 수동으로 최적화하려면 shouldComponentUpdate()
를 사용해야 합니다. 🎜🎜🎜🎜확장: React Hooks를 아시나요? 🎜🎜🎜컴포넌트 클래스 작성이 매우 무겁고 레벨이 너무 많으면 유지 관리가 어렵습니다. 🎜🎜함수 구성 요소는 순수 함수이고 상태를 포함할 수 없으며 수명 주기 메서드를 지원하지 않으므로 클래스를 대체할 수 없습니다. 🎜🎜🎜React Hooks의 설계 목적은 "클래스"를 전혀 사용하지 않고도 모든 기능을 갖춘 구성 요소를 작성할 수 있다는 것을 의미합니다. 외부 구성 요소가 필요한 경우 기능 및 부작용을 위해 후크를 사용하여 외부 코드를 "연결"합니다. 🎜🎜patchKeyedChildren
이라고 합니다. 이 함수는 핵심 diff 알고리즘을 구현하는 데 익숙한 곳입니다. 일반적인 프로세스는 헤드 노드를 동기화하고 처리하는 것입니다. 노드 추가 및 삭제, 마지막으로 가장 긴 증가 부분 수열을 해결하는 방법을 사용하여 알려지지 않은 부분 수열을 처리합니다. 이는 기존 노드의 재사용을 극대화하고 DOM 작업의 성능 오버헤드를 줄이며 내부 업데이트로 인해 발생하는 하위 노드 상태 오류 문제를 방지하기 위한 것입니다. 🎜🎜결론적으로 v-for를 사용하여 상수를 순회하거나 하위 노드가 일반 텍스트와 같이 "상태"가 없는 노드인 경우 키를 추가하지 않고도 쓰기 방법을 사용할 수 있습니다. 그러나 실제 개발 과정에서는 키를 균일하게 추가하는 것이 좋습니다. 그러면 더 넓은 범위의 시나리오를 실현하고 가능한 상태 업데이트 오류를 피할 수 있습니다. 일반적으로 ESlint를 사용하여 키를 v-for의 필수 요소로 구성할 수 있습니다. 🎜想详细了解这个知识点的可以去看看我之前写的文章:v-for 到底为啥要加上 key?
vue2使用的是Object.defineProperty
去监听对象属性值的变化,但是它不能监听对象属性的新增和删除,所以需要使用$set
、$delete
这种语法糖去实现,这其实是一种设计上的不足。
所以 vue3 采用了proxy
去实现响应式监听对象属性的增删查改。
其实从api的原生性能上proxy
是比Object.defineProperty
要差的。
而 vue 做的响应式性能优化主要是在将嵌套层级比较深的对象变成响应式的这一过程。
vue2的做法是在组件初始化的时候就递归执行Object.defineProperty
把子对象变成响应式的;
而vue3是在访问到子对象属性的时候,才会去将它转换为响应式。这种延时定义子对象响应式会对性能有一定的提升
前提:当同类型的 vnode 的子节点都是一组节点(数组类型)的时候,
步骤:会走核心 diff 流程
Vue3是快速选择算法
Vue2是双端比较算法
在新旧字节点的头尾节点,也就是四个节点之间进行对比,找到可复用的节点,不断向中间靠拢的过程
diff目的:diff 算法的目的就是为了尽可能地复用节点,减少 DOM 频繁创建和删除带来的性能开销
基于 MVVM 模型,viewModel(业务逻辑层)提供了数据变化后更新视图和视图变化后更新数据这样一个功能,就是传统意义上的双向绑定。
Vue2.x 实现双向绑定核心是通过三个模块:Observer监听器、Watcher订阅者和Compile编译器。
首先监听器会监听所有的响应式对象属性,编译器会将模板进行编译,找到里面动态绑定的响应式数据并初始化视图;watchr 会去收集这些依赖;当响应式数据发生变更时Observer就会通知 Watcher;watcher接收到监听器的信号就会执行更新函数去更新视图;
vue3的变更是数据劫持部分使用了porxy 替代 Object.defineProperty,收集的依赖使用组件的副作用渲染函数替代watcher
vue2 v-model 原理剖析
V-model 是用来监听用户事件然后更新数据的语法糖。
其本质还是单向数据流,内部是通过绑定元素的 value 值向下传递数据,然后通过绑定 input 事件,向上接收并处理更新数据。
单向数据流:父组件传递给子组件的值子组件不能修改,只能通过emit事件让父组件自个改。
// 比如 <input v-model="sth" /> // 等价于 <input :value="sth" @input="sth = $event.target.value" />
给组件添加 v-model
属性时,默认会把value
作为组件的属性,把 input
作为给组件绑定事件时的事件名:
// 父组件 <my-button v-model="number"></my-button> // 子组件 <script> export default { props: { value: Number, // 属性名必须是 value }, methods: { add() { this.$emit('input', this.value + 1) // 事件名必须是 input }, } } </script>
如果想给绑定的 value 属性和 input 事件换个名称呢?可以这样:
在 Vue 2.2 及以上版本,你可以在定义组件时通过 model 选项的方式来定制 prop/event:
<script> export default { model: { prop: 'num', // 自定义属性名 event: 'addNum' // 自定义事件名 } }
vue3 v-model 原理
实现和 vue2 基本一致
<Son v-model="modalValue"/>
等同于
<Son v-model="modalValue"/>
自定义 model 参数
<Son v-model:visible="visible"/> setup(props, ctx){ ctx.emit("update:visible", false) }
不管vue2 还是 vue3,响应式的核心就是观察者模式 + 劫持数据的变化,在访问的时候做依赖收集和在修改数据的时候执行收集的依赖并更新数据。具体点就是:
vue2 的话采用的是 Object.definePorperty
劫持对象的 get 和 set 方法,每个组件实例都会在渲染时初始化一个 watcher 实例,它会将组件渲染过程中所接触的响应式变量记为依赖,并且保存了组件的更新方法 update。当依赖的 setter 触发时,会通知 watcher 触发组件的 update 方法,从而更新视图。
Vue3 使用的是 ES6 的 proxy,proxy 不仅能够追踪属性的获取和修改,还可以追踪对象的增删,这在 vue2中需要 delete 才能实现。然后就是收集的依赖是用组件的副作用渲染函数替代 watcher 实例。
性能方面,从原生 api 角度,proxy 这个方法的性能是不如 Object.property,但是 vue3 强就强在一个是上面提到的可以追踪对象的增删,第二个是对嵌套对象的处理上是访问到具体属性才会把那个对象属性给转换成响应式,而 vue2 是在初始化的时候就递归调用将整个对象和他的属性都变成响应式,这部分就差了。
扩展一
vue2 通过数组下标更改数组视图为什么不会更新?
尤大:性能不好
注意:vue3 是没问题的
why 性能不好?
我们看一下响应式处理:
export class Observer { this.value = value this.dep = new Dep() this.vmCount = 0 def(value, '__ob__', this) if (Array.isArray(value)) { // 这里对数组进行单独处理 if (hasProto) { protoAugment(value, arrayMethods) } else { copyAugment(value, arrayMethods, arrayKeys) } this.observeArray(value) } else { // 对对象遍历所有键值 this.walk(value) } } walk (obj: Object) { const keys = Object.keys(obj) for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]) } } observeArray (items: Array<any>) { for (let i = 0, l = items.length; i < l; i++) { observe(items[i]) } } }
对于对象是通过Object.keys()
遍历全部的键值,对数组只是observe
监听已有的元素,所以通过下标更改不会触发响应式更新。
理由是数组的键相较对象多很多,当数组数据大的时候性能会很拉胯。所以不开放
Computed 的大体实现和普通的响应式数据是一致的,不过加了延时计算和缓存的功能:
在访问computed对象的时候,会触发 getter ,初始化的时候将 computed 属性创建的 watcher (vue3是副作用渲染函数)添加到与之相关的响应式数据的依赖收集器中(dep),然后根据里面一个叫 dirty 的属性判断是否要收集依赖,不需要的话直接返回上一次的计算结果,需要的话就执行更新重新渲染视图。
watchEffect?
watchEffect会自动收集回调函数中响应式变量的依赖。并在首次自动执行
推荐在大部分时候用 watch
显式的指定依赖以避免不必要的重复触发,也避免在后续代码修改或重构时不小心引入新的依赖。watchEffect
适用于一些逻辑相对简单,依赖源和逻辑强相关的场景(或者懒惰的场景 )
vue有个机制,更新 DOM 是异步执行的,当数据变化会产生一个异步更行队列,要等异步队列结束后才会统一进行更新视图,所以改了数据之后立即去拿 dom 还没有更新就会拿不到最新数据。所以提供了一个 nextTick 函数,它的回调函数会在DOM 更新后立即执行。
nextTick 本质上是个异步任务,由于事件循环机制,异步任务的回调总是在同步任务执行完成后才得到执行。所以源码实现就是根据环境创建异步函数比如 Promise.then(浏览器不支持promise就会用MutationObserver,浏览器不支持MutationObserver就会用setTimeout),然后调用异步函数执行回调队列。
所以项目中不使用$nextTick的话也可以直接使用Promise.then或者SetTimeout实现相同的效果
1、全局错误处理:Vue.config.errorHandler
Vue.config.errorHandler = function(err, vm, info) {};
如果在组件渲染时出现运行错误,错误将会被传递至全局Vue.config.errorHandler
配置函数 (如果已设置)。
比如前端监控领域的 sentry,就是利用这个钩子函数进行的 vue 相关异常捕捉处理
2、全局警告处理:Vue.config.warnHandler
Vue.config.warnHandler = function(msg, vm, trace) {};
注意:仅在开发环境生效
像在模板中引用一个没有定义的变量,它就会有warning
3、单个vue 实例错误处理:renderError
const app = new Vue({ el: "#app", renderError(h, err) { return h("pre", { style: { color: "red" } }, err.stack); } });
和组件相关,只适用于开发环境,这个用处不是很大,不如直接看控制台
4、子孙组件错误处理:errorCaptured
Vue.component("cat", { template: `<div><slot></slot></div>`, props: { name: { type: string } }, errorCaptured(err, vm, info) { console.log(`cat EC: ${err.toString()}\ninfo: ${info}`); return false; } });
注:只能在组件内部使用,用于捕获子孙组件的错误,一般可以用于组件开发过程中的错误处理
5、终极错误捕捉:window.onerror
window.onerror = function(message, source, line, column, error) {};
它是一个全局的异常处理函数,可以抓取所有的 JavaScript 异常
Vuex 利用 vue 的mixin 机制,在beforeCreate 钩子前混入了 vuexinit 方法,这个方法实现了将 store 注入 vue 实例当中,并注册了 store 的引用属性 store.xxx`去引入vuex中定义的内容。
然后 state 是利用 vue 的 data,通过new Vue({data: {$$state: state}}
将 state 转换成响应式对象,然后使用 computed 函数实时计算 getter
概念
可以通过全局方法Vue.use()
注册插件,并能阻止多次注册相同插件,它需要在new Vue
之前使用。
该方法第一个参数必须是Object
或Function
类型的参数。如果是Object
那么该Object
需要定义一个install
方法;如果是Function
那么这个函数就被当做install
方法。
Vue.use()
执行就是执行install
方法,其他传参会作为install
方法的参数执行。
所以**Vue.use()
本质就是执行需要注入插件的install
方法**。
源码实现
export function initUse (Vue: GlobalAPI) { Vue.use = function (plugin: Function | Object) { const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) // 避免重复注册 if (installedPlugins.indexOf(plugin) > -1) { return this } // 获取传入的第一个参数 const args = toArray(arguments, 1) args.unshift(this) if (typeof plugin.install === 'function') { // 如果传入对象中的install属性是个函数则直接执行 plugin.install.apply(plugin, args) } else if (typeof plugin === 'function') { // 如果传入的是函数,则直接(作为install方法)执行 plugin.apply(null, args) } // 将已经注册的插件推入全局installedPlugins中 installedPlugins.push(plugin) return this } }
使用方式
installedPlugins import Vue from 'vue' import Element from 'element-ui' Vue.use(Element)
要暴露一个install
方法,第一个参数是Vue
构造器,第二个参数是一个可选的配置项对象
Myplugin.install = function(Vue, options = {}) { // 1、添加全局方法或属性 Vue.myGlobalMethod = function() {} // 2、添加全局服务 Vue.directive('my-directive', { bind(el, binding, vnode, pldVnode) {} }) // 3、注入组件选项 Vue.mixin({ created: function() {} }) // 4、添加实例方法 Vue.prototype.$myMethod = function(methodOptions) {} }
Css直接面试问答的题目相对来说比较少,更多的是需要你能够当场手敲代码实现功能,一般来说备一些常见的布局,熟练掌握flex基本就没有什么问题了。
Block Formatting context,块级格式上下文
BFC 是一个独立的渲染区域,相当于一个容器,在这个容器中的样式布局不会受到外界的影响。
比如浮动元素、绝对定位、overflow 除 visble 以外的值、display 为 inline/tabel-cells/flex 都能构建 BFC。
常常用于解决
处于同一个 BFC 的元素外边距会产生重叠(此时需要将它们放在不同 BFC 中);
清除浮动(float),使用 BFC 包裹浮动的元素即可
阻止元素被浮动元素覆盖,应用于两列式布局,左边宽度固定,右边内容自适应宽度(左边float,右边 overflow)
伪类
伪类即:当元素处于特定状态时才会运用的特殊类
开头为冒号的选择器,用于选择处于特定状态的元素。比如:first-child
选择第一个子元素;:hover
悬浮在元素上会显示;:focus
用键盘选定元素时激活;:link
+ :visted
点击过的链接的样式;:not
用于匹配不符合参数选择器的元素;:fist-child
匹配元素的第一个子元素;:disabled
匹配禁用的表单元素
伪元素
伪元素用于创建一些不在文档树中的元素,并为其添加样式。比如说,我们可以通过::before
来在一个元素前增加一些文本,并为这些文本添加样式。虽然用户可以看到这些文本,但是这些文本实际上不在文档树中。示例:
::before
在被选元素前插入内容。需要使用 content 属性来指定要插入的内容。被插入的内容实际上不在文档树中
h1:before { content: "Hello "; }
::first-line
匹配元素中第一行的文本
href是Hypertext Reference的简写,表示超文本引用,指向网络资源所在位置。href 用于在当前文档和引用资源之间确立联系
src是source的简写,目的是要把文件下载到html页面中去。src 用于替换当前内容
浏览器解析方式
当浏览器遇到href会并行下载资源并且不会停止对当前文档的处理。(同时也是为什么建议使用 link 方式加载 CSS,而不是使用 @import 方式)
当浏览器解析到src ,会暂停其他资源的下载和处理,直到将该资源加载或执行完毕。(这也是script标签为什么放在底部而不是头部的原因)
flex
<div class="wrapper flex-center"> <p>horizontal and vertical</p> </div> .wrapper { width: 900px; height: 300px; border: 1px solid #ccc; } .flex-center { // 注意是父元素 display: flex; justify-content: center; // 主轴(竖线)上的对齐方式 align-items: center; // 交叉轴(横轴)上的对齐方式 }
flex + margin
<div class="wrapper"> <p>horizontal and vertical</p> </div> .wrapper { width: 900px; height: 300px; border: 1px solid #ccc; display: flex; } .wrapper > p { margin: auto; }
Transform + absolute
<div class="wrapper"> <img src="test.png" alt="3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인" > </div> .wrapper { width: 300px; height: 300px; border: 1px solid #ccc; position: relative; } .wrapper > img { position: absolute; left: 50%; top: 50%; tansform: translate(-50%, -50%) }
注:使用该方法只适用于行内元素(a、img、label、br、select等)(宽度随元素的内容变化而变化),用于块级元素(独占一行)会有问题,left/top 的50%是基于图片最左侧的边来移动的,tanslate会将多移动的图片自身的半个长宽移动回去,就实现了水平垂直居中的效果
display: table-cell
<div class="wrapper"> <p>absghjdgalsjdbhaksldjba</p> </div> .wrapper { width: 900px; height: 300px; border: 1px solid #ccc; display: table-cell; vertical-align: middle; text-align: center; }
浏览器和网络是八股中最典型的案例了,无论你是几年经验,只要是前端,总会有问到你的浏览器和网络协议。
最好的学习文章是李兵老师的《浏览器工作原理与实践》
这里分了同源页面和不同源页面的通信。
不同源页面可以通过 iframe 作为一个桥梁,因为 iframe 可以指定 origin 来忽略同源限制,所以可以在每个页面都嵌入同一个 iframe 然后监听 iframe 中传递的 message 就可以了。
同源页面的通信大致分为了三类:广播模式、共享存储模式和口口相传模式
第一种广播模式,就是可以通过 BroadCast Channel、Service Worker 或者 localStorage 作为广播,然后去监听广播事件中消息的变化,达到页面通信的效果。
第二种是共享存储模式,我们可以通过Shared Worker 或者 IndexedDB,创建全局共享的数据存储。然后再通过轮询去定时获取这些被存储的数据是否有变更,达到一个的通信效果。像常见cookie 也可以作为实现共享存储达到页面通信的一种方式
最后一种是口口相传模式,这个主要是在使用 window.open 的时候,会返回被打开页面的 window 的引用,而在被打开的页面可以通过 window.opener 获取打开它的页面的 window 点引用,这样,多个页面之间的 window 是能够相互获取到的,传递消息的话通过 postMessage 去传递再做一个事件监听就可以了
在浏览器第一次发起请求服务的过程中,会根据响应报文中的缓存标识决定是否缓存结果,是否将缓存标识和请求结果存入到浏览器缓存中。
HTTP 缓存分为强制缓存和协商缓存两类。
强制缓存就是请求的时候浏览器向缓存查找这次请求的结果,这里分了三种情况,没查找到直接发起请求(和第一次请求一致);查找到了并且缓存结果还没有失效就直接使用缓存结果;查找到但是缓存结果失效了就会使用协商缓存。
强制缓存有 Expires 和 Cache-control 两个缓存标识,Expires 是http/1.0 的字段,是用来指定过期的具体的一个时间(如 Fri, 02 Sep 2022 08:03:35 GMT),当服务器时间和浏览器时间不一致的话,就会出现问题。所以在 http1.1 添加了 cache-control 这个字段,它的值规定了缓存的范围(public/private/no-cache/no-store),也可以规定缓存在xxx时间内失效(max-age=xxx)是个相对值,就能避免了 expires带来的问题。
캐시 협상은 캐시된 결과를 강제로 무효화하는 프로세스입니다. 브라우저는 캐시 식별자를 전달하여 서버에 요청을 시작하고, 서버는 캐시 식별자를 통해 캐시를 사용할지 여부를 결정합니다.
협상 캐시를 제어하는 필드는 last-modified / if-modified-since 및 Etag / if-none-match이며 후자가 더 높은 우선순위를 갖습니다.
일반적인 프로세스는 요청 메시지를 통해 last-modified 또는 Etag 값을 서버에 전달하고 결과가 if-modified-since 또는 if-none-과 일치하는 경우 서버의 해당 값과 비교하는 것입니다. 응답 메시지에서 일치한 다음 협상 캐시가 유효하고 캐시된 결과를 사용하고 304를 반환합니다. 그렇지 않으면 유효하지 않으며 결과를 다시 요청하고 200을 반환합니다.
사용자가 콘텐츠를 입력하면 브라우저는 먼저 해당 콘텐츠가 검색인지 여부를 결정합니다. 콘텐츠가 여전히 검색 콘텐츠인 경우 기본 검색 엔진과 결합되어 URL을 생성합니다. 예를 들어 Google 브라우저는 goole.com/search?xxxx입니다. URL인 경우 http/https와 같이 프로토콜이 결합됩니다. 페이지가 beforeupload 시간을 수신하지 않거나 실행 프로세스를 계속하는 데 동의하면 브라우저 아이콘 표시줄이 로딩 상태로 들어갑니다.
다음으로, 브라우저 프로세스는 IPC 프로세스 간 통신을 통해 네트워크 프로세스에 URL 요청을 보냅니다. 네트워크 프로세스는 먼저 캐시에서 리소스를 검색하고 요청을 가로채서 200을 직접 반환합니다. 그렇지 않은 경우 네트워크 요청 프로세스로 들어갑니다.
네트워크 요청 프로세스는 네트워크 프로세스가 도메인 이름에 해당하는 IP 및 포트 번호를 반환하도록 DNS 서버에 요청하는 것입니다(이전에 캐시된 경우 포트 번호가 없으면 캐시된 결과가 직접 반환됩니다). , http의 기본값은 80, https의 기본값은 443입니다. https인 경우 암호화된 데이터 채널을 생성하려면 TLS 보안 연결도 설정해야 합니다.
그런 다음 TCP 3방향 핸드셰이크가 브라우저와 서버 간의 연결을 설정한 다음 데이터 전송을 수행합니다. 데이터 전송이 완료된 후 손을 네 번 흔들어 연결을 끊으면 언제든지 연결을 유지할 수 있습니다. 연결. connection: keep-alive
페이지 렌더링 프로세스(키 메모리)
마지막으로 렌더링 프로세스는 문서의 페이지 구문 분석 및 하위 리소스 로딩을 수행합니다. 렌더링 프로세스는 HTML을 DOM 트리 구조로 변환하고 CSS를 styleSeets(CSSOM)으로 변환합니다. 그런 다음 DOM 트리를 복사하고 표시되지 않는 요소를 필터링하여 기본 렌더링 트리를 만듭니다. 그런 다음 각 DOM 노드의 스타일을 계산하고 각 노드의 위치 레이아웃 정보를 계산하여 레이아웃 트리를 만듭니다. 레이어링 컨텍스트가 있거나 자르기가 필요한 경우 레이어가 독립적으로 생성되며, 이는 결국 레이어 트리를 형성하게 됩니다. 렌더링 프로세스는 각 레이어에 대한 드로잉 목록을 생성하여 합성 스레드에 제출합니다. 합성 스레드는 레이어를 타일로 나누고(레이어의 모든 내용을 한 번에 그리는 것을 방지하고 뷰포트 부분을 타일 우선순위에 따라 렌더링할 수 있음) 타일을 래스터화 스레드 풀에서 비트맵으로 변환합니다. . 변환이 완료된 후 합성 스레드는 드로잉 블록 명령 DrawQuard를 브라우저 프로세스로 보냅니다. 브라우저는 DrawQuard 메시지를 기반으로 페이지를 생성하여 브라우저에 표시합니다.약어:
브라우저의 렌더링 프로세스는 html을 dom 트리로 구문 분석하고, css를 cssom 트리로 구문 분석합니다. 그런 다음 먼저 DOM 트리를 복사하여 표시되지 않는 요소(예: display: none)를 필터링합니다. 그런 다음 cssom을 결합하여 각 DOM 노드의 레이아웃 정보를 결합하고 계산하여 레이아웃 트리를 만듭니다. 레이아웃 트리가 생성된 후 레이어의 스택 컨텍스트에 따라 레이어링되거나 잘린 부분이 레이어드 트리를 형성합니다. 그런 다음 렌더링 프로세스에서는 각 레이어에 대한 도면 목록을 생성하고 이를 컴포지션 스레드에 제출합니다. 일회성 렌더링을 방지하기 위해 컴포지션 스레드는 레이어를 타일로 나누고 래스터화를 통해 타일을 변환합니다. 스레드 풀. 변환이 완료된 후 합성 스레드는 표시를 위해 브라우저에 타일을 그리는 명령을 보냅니다UDP는 User Datagram Protocol(User Dataprogram Protocol)입니다. IP는 IP 주소 정보를 통해 지정된 컴퓨터로 데이터 패킷을 전송한 후 UDP가 데이터 패킷을 올바른 컴퓨터로 배포할 수 있습니다. 포트 번호 프로그램을 통해. UDP는 데이터가 올바른지 확인할 수 있지만 재전송 메커니즘이 없으며 잘못된 데이터 패킷만 폐기합니다. 동시에 UDP는 데이터를 보낸 후 대상에 도달했는지 여부를 확인할 수 없습니다. UDP는 데이터의 신뢰성을 보장할 수는 없으나 전송 속도가 매우 빠르기 때문에 데이터 무결성을 엄격하게 보장하지 못하는 온라인 동영상, 대화형 게임 등의 영역에서 주로 사용됩니다.
TCP는 UDP 데이터가 손실되기 쉽고 데이터 패킷을 올바르게 조립할 수 없는 문제를 해결하기 위해 도입된 전송 제어 프로토콜(Transmission Control Protocol)입니다. 연결 지향적이고 안정적인 바이트 스트림 기반 전송 계층 통신 프로토콜입니다. . TCP는 패킷 손실을 처리하기 위한 재전송 메커니즘을 제공하고, TCP는 순서가 잘못된 데이터 패킷을 완전한 파일로 결합할 수 있는 패킷 정렬 메커니즘을 도입합니다.
TCP 헤더는 대상 포트와 로컬 포트 번호 외에도 정렬을 위한 시퀀스 번호도 제공하므로 수신측에서는 시퀀스 번호를 통해 데이터 패킷을 재정렬할 수 있습니다.
TCP 연결의 수명주기는 링크 단계, 데이터 전송 및 연결 해제 단계의 세 단계를 거칩니다.
연결 단계
는 클라이언트와 서버 간의 링크를 설정하는 데 사용됩니다. 3방향 핸드셰이크는 클라이언트와 서버 간의 데이터 패킷 송수신 기능을 확인하는 데 사용됩니다.
1. 클라이언트는 먼저 SYN 메시지를 보내 서버가 데이터를 보낼 수 있음을 확인하고 SYN_SENT 상태로 들어가 서버의 확인을 기다립니다.
2. 서버가 SYN 메시지를 받으면 ACK를 보냅니다. 동시에 서버는 클라이언트에게 SYN 메시지를 보내 클라이언트가 데이터를 보낼 수 있는지 확인합니다. 이때 서버는 클라이언트가 수신하면 SYN_RCVD 상태로 들어갑니다. ACK + SYN 메시지는 서버에 메시지를 보냅니다. 데이터 패킷을 보내고 ESTABLISHED 상태로 들어갑니다(연결 설정). 서버가 클라이언트가 보낸 ACK 패킷을 받으면 ESTABLISHED 상태로 들어가고 완료됩니다. the three-way handshake
데이터 전송 단계이 단계에서는 수신 측에서 각 패킷을 처리해야 합니다. 확인 작업을 수행합니다. 지정된 시간 내에 수신자가 수신하면 패킷 손실로 판단되어 재전송 메커니즘이 시작됩니다.
대용량 파일이 있습니다. 전송 과정에서 데이터 패킷이 목적지에 도착한 후 여러 개의 작은 데이터 패킷으로 나뉩니다. 수신 측에서는 데이터 무결성을 보장하기 위해 TCP 헤더의 시퀀스 번호에 따라 정렬됩니다.
연결 해제 단계양쪽이 설정한 연결이 끊어질 수 있도록 4번 웨이브1 클라이언트가 서버에 FIN 패킷을 시작하고 FIN_WAIT_1 상태로 들어갑니다
2. 패킷을 보내고 자신의 시퀀스 번호가 포함된 확인 패킷 ACK를 보내면 서버는 CLOSE_WAIT 상태로 들어갑니다. 이때 클라이언트는 서버로 보낼 데이터가 없지만 서버가 클라이언트로 보낼 데이터가 있는 경우 클라이언트는 이를 수신해야 합니다. ACK를 받은 후 클라이언트는 FIN_WAIT_2 상태로 들어갑니다
3. 서버는 데이터 전송을 완료한 후 FIN 패킷을 클라이언트로 보냅니다. 이때 서버는 LAST_ACK 상태로 들어갑니다
4. FIN 패킷을 전송하고 확인 패킷 ACK를 보냅니다. 이때 클라이언트는 TIME_WAIT 상태로 진입하고 2MSL을 기다린 후 CLOSED 상태로 진입합니다. 서버는 클라이언트의 ACK를 받은 후 CLOSED 상태로 진입합니다.
4개의 웨이브의 경우 TCP는 전이중 통신이므로 활성 종료 당사자가 FIN 패킷을 보낸 후에도 수신 측에서는 여전히 데이터를 보낼 수 있으며 서버에서 클라이언트로의 데이터 채널을 즉시 닫을 수 없으므로 서버는 -side can be FIN
패킷은 ACK
패킷과 함께 클라이언트로 전송됩니다. ACK
는 먼저 확인될 수 있으며 그 다음에는 서버는 FIN 패킷을 보낼 필요가 없을 때까지 를 보내지 않으므로 4개의 웨이브는 4개의 데이터 패킷 상호 작용이어야 합니다</p><h4 data-id="heading-50"><p>Content-length Do 이해해요? </p><p><code>FIN
包与对客户端的 ACK
包合并发送,只能先确认 ACK
,然后服务器待无需发送数据时再发送 FIN
包,所以四次挥手时必须是四次数据包的交互
Content-length 是 http 消息长度,用十进制数字表示的字节的数目。
如果 content-length > 实际长度,服务端/客户端读取到消息队尾时会继续等待下一个字节,会出现无响应超时的情况
如果 content-length < 实际长度,首次请求的消息会被截取,然后会导致后续的数据解析混乱。
当不确定content-length的值应该使用Transfer-Encoding: chunked,能够将需要返回的数据分成多个数据块,直到返回长度为 0 的终止块
什么是跨域?
协议 + 域名 + 端口号均相同时则为同域,任意一个不同则为跨域
解决方案
1、 传统的jsonp:利用<script>
Content-length는 http 메시지 길이로, 십진수로 표현된 바이트 수입니다.
2、 一般使用 cors(跨域资源共享)来解决跨域问题,浏览器在请求头中发送origin字段指明请求发起的地址,服务端返回Access-control-allow-orign,如果一致的话就可以进行跨域访问
3、 Iframe 解决主域名相同,子域名不同的跨域请求
4、 浏览器关闭跨域限制的功能
5、 http-proxy-middleware 代理
预检
补充:http会在跨域的时候发起一次预检请求,“需预检的请求”要求必须首先使用OPTIONS方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。“预检请求”的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。
withCredentials为 true不会产生预请求;content-type为application/json会产生预请求;设置了用户自定义请求头会产生预检请求;delete方法会产生预检请求;
xss基本概念
Xss (Cross site scripting)跨站脚本攻击,为了和 css 区别开来所以叫 xss
Xss 指黑客向 html 或 dom 中注入恶意脚本,从而在用户浏览页面的时候利用注入脚本对用户实施攻击的手段
恶意脚本可以做到:窃取 cookie 信息、监听用户行为(比如表单的输入)、修改DOM(比如伪造登录界面骗用户输入账号密码)、在页面生成浮窗广告等
恶意脚本注入方式:
存储型 xss
黑客利用站点漏洞将恶意 js 代码提交到站点服务器,用户访问页面就会导致恶意脚本获取用户的cookie等信息。
反射性 xss
用户将一段恶意代码请求提交给 web 服务器,web 服务器接收到请求后将恶意代码反射到浏览器端
基于 DOM 的 xss 攻击
通过网络劫持在页面传输过程中更改 HTML 内容
前两种属于服务端漏洞,最后一种属于前端漏洞
防止xss攻击的策略
1、服务器对输入脚本进行过滤或者转码,比如将code:<script>alert('你被xss攻击了')
转换成code:<script>alert('你被xss攻击了')
2、充分利用内容安全策略 CSP(content-security-policy),可以通过 http 头信息的 content-security-policy 字段控制可以加载和执行的外部资源;或者通过html的meta 标签<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
3、cookie设置为 http-only, cookie 就无法通过 document.cookie
来读取
csrf基本概念
Csrf(cross site request forgery)跨站请求伪造,指黑客引导用户访问黑客的网站。
CSRF 是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。简单来讲,CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事。
Csrf 攻击场景
自动发起 get 请求
比如黑客网站有个图片:
<img src="https://time.geekbang.org/sendcoin?user=hacker&number=100" alt="3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인" >
黑客将转账的请求接口隐藏在 img 标签内,欺骗浏览器这是一张图片资源。当该页面被加载时,浏览器会自动发起 img 的资源请求,如果服务器没有对该请求做判断的话,那么服务器就会认为该请求是一个转账请求,于是用户账户上的 100 极客币就被转移到黑客的账户上去了。
自动发起 post 请求
黑客在页面中构建一个隐藏的表单,当用户点开链接后,表单自动提交
引诱用户点击链接
比如页面上放了一张美女图片,下面放了图片下载地址,而这个下载地址实际上是黑客用来转账的接口,一旦用户点击了这个链接,那么他的极客币就被转到黑客账户上了
防止csrf方法
1、设置 cookie 时带上SameSite: strict/Lax选项
2、验证请求的来源站点,通过 origin 和 refere 判断来源站点信息
3、csrf token,浏览器发起请求服务器生成csrf token,发起请求前会验证 csrf token是否合法。第三方网站肯定是拿不到这个token。我们的 csrf token 是前后端约定好后写死的。
websocket是一种支持双向通信的协议,就是服务器可以主动向客户端发消息,客户端也可以主动向服务器发消息。
HTTP 프로토콜을 기반으로 연결을 설정하므로 HTTP 프로토콜과 잘 호환되므로 동일 출처 제한이 없습니다.
WebSocket은 이벤트 중심 프로토콜이므로 진정한 실시간 통신에 사용할 수 있습니다. 업데이트를 지속적으로 요청해야 하는 HTTP와 달리 웹소켓을 사용하면 업데이트가 제공되는 즉시 전송됩니다.
웹소켓은 연결이 종료될 때 자동으로 복구되지 않습니다. 이는 애플리케이션 개발에서 직접 구현해야 하는 메커니즘입니다. , 클라이언트 측 오픈 소스 라이브러리가 필요한 이유 중 하나는 많습니다.
webpack 및 vite와 같은 devServer는 웹소켓을 사용하여 핫 업데이트를 구현합니다.
성능 최적화는 중견기업과 대기업이 크게 주목하는 포인트입니다. 프론트엔드 인력의 KPI와도 밀접한 관련이 있기 때문에 자연스럽게 면접 질문이 잦아지게 됩니다.
캐싱의 관점에서
네트워크에서는 정적 리소스에 CDN을 사용하는 것이 더 일반적입니다
패키징 측면에서
코드 수준
첫 번째 화면 속도 향상
vue 일반적인 성능 최적화 방법
window.performance
를 통해 다양한 성과 지표 데이터를 얻을 수 있습니다. 완전한 프런트엔드 모니터링 플랫폼에는 다음이 포함됩니다: 데이터 수집 및 보고, 데이터 정렬 및 저장, 데이터 표시
웹 페이지 성능 지표:
위 지표는 PerformanceObserver
를 통해 얻을 수 있습니다.首屏渲染时间计算:通过MutationObserver
监听document
对象的属性变化
首先应该避免直接使用 DOM API 操作 DOM,像 vue react 虚拟 DOM 让对 DOM 的多次操作合并成了一次。
样式集中改变,好的方式是使用动态 class
读写操作分离,避免读后写,写后又读
// bad 强制刷新 触发四次重排+重绘 div.style.left = div.offsetLeft + 1 + 'px'; div.style.top = div.offsetTop + 1 + 'px'; div.style.right = div.offsetRight + 1 + 'px'; div.style.bottom = div.offsetBottom + 1 + 'px'; // good 缓存布局信息 相当于读写分离 触发一次重排+重绘 var curLeft = div.offsetLeft; var curTop = div.offsetTop; var curRight = div.offsetRight; var curBottom = div.offsetBottom; div.style.left = curLeft + 1 + 'px'; div.style.top = curTop + 1 + 'px'; div.style.right = curRight + 1 + 'px'; div.style.bottom = curBottom + 1 + 'px';
原来的操作会导致四次重排,读写分离之后实际上只触发了一次重排,这都得益于浏览器的渲染队列机制:
当我们修改了元素的几何属性,导致浏览器触发重排或重绘时。它会把该操作放进渲染队列,等到队列中的操作到了一定的数量或者到了一定的时间间隔时,浏览器就会批量执行这些操作。
使用display: none
后元素不会存在渲染树中,这时对它进行各种操作,然后更改 display 显示即可(示例:向2000个div中插入一个div)
通过 documentFragment 创建 dom 片段,在它上面批量操作 dom ,操作完后再添加到文档中,这样只有一次重排(示例:一次性插入2000个div)
复制节点在副本上操作然后替换它
使用 BFC 脱离文档流,重排开销小
Css 中的transform
、opacity
、filter
、will-change
能触发硬件加速
优化请求数
background-url
和backgroun-position
来显示图标background-url
来懒加载减小图片大小
缓存
非响应式变量可以定义在created
钩子中使用 this.xxx 赋值
访问局部变量比全局变量块,因为不需要切换作用域
尽可能使用 const
声明变量,注意数组和对象
使用 v8 引擎时,运行期间,V8 会将创建的对象与隐藏类关联起来,以追踪它们的属性特征。能够共享相同隐藏类的对象性能会更好,v8 会针对这种情况去优化。所以为了贴合”共享隐藏类“,我们要避免”先创建再补充“式的动态属性复制以及动态删除属性(使用delete关键字)。即尽量在构造函数/对象中一次性声明所有属性。属性删除时可以设置为 null,这样可以保持隐藏类不变和继续共享。
避免内存泄露的方式
避免强制同步,在修改 DOM 之前查询相关值
避免布局抖动(一次 JS 执行过程中多次执行强制布局和抖动操作),尽量不要在修改 DOM 结构时再去查询一些相关值
合理利用 css 合成动画,如果能用 css 处理就交给 css。因为合成动画会由合成线程执行,不会占用主线程
避免频繁的垃圾回收,优化存储结构,避免小颗粒对象的产生
感兴趣的可以看看我之前的一篇性能优化技巧整理的文章极意 · 代码性能优化之道
프론트엔드 엔지니어링은 프론트엔드 ER 성장에 있어서 가장 필수적인 스킬 포인트입니다. 프런트엔드 개발 효율성을 높일 수 있는 모든 기능은 프론트엔드의 일부라고 볼 수 있습니다. 엔지니어링을 종료합니다. 이제 막 시작한 사람들은 스캐폴딩을 처음부터 구축하는 것부터 시작할 수 있습니다10,000 단어에 달하는 긴 글은 엔터프라이즈급 vue3 + vite2+ ts4 프레임워크를 처음부터 구축하는 전체 과정을 자세히 설명합니다
인터뷰에서 가장 중요한 것은 시험은 포장 도구의 숙달입니다.
webpack은 최신 JS 애플리케이션에 정적 리소스 패키징 기능을 제공하는 번들입니다.
핵심 프로세스는 초기화 단계, 구성 단계 및 생성 단계의 세 단계로 구성됩니다.
1 초기화 단계에서는 구성 파일, 구성 개체 및 셸 매개변수에서 초기화 매개변수를 읽어 기본 구성과 결합하여 구성합니다. 최종 매개변수는 물론 컴파일러 개체를 생성하고 실행 환경을 초기화합니다
2. 컴파일러는 run() 메서드를 실행하여 컴파일 프로세스를 시작합니다. 항목 파일에서 항목 파일 검색을 시작합니다. 직접 또는 간략하게 연관된 모든 파일에 대한 종속 개체를 생성한 다음 종속 개체를 기반으로 모듈 개체를 생성합니다. 이때 로더는 모듈을 표준으로 변환하는 데 사용됩니다. js 콘텐츠를 호출한 다음 js 인터프리터를 호출하여 콘텐츠를 AST 개체로 변환한 다음 AST에서 모듈이 의존하는 모듈을 찾고 모든 항목 종속성 파일이 이 단계에서 처리될 때까지 이 단계를 반복합니다. 마지막으로 모듈 컴파일이 완료되고, 각 모듈의 번역된 내용과 이들 사이의 종속성 그래프가 얻어집니다. 이 종속성 그래프는 프로젝트에 사용되는 모든 모듈의 매핑 관계입니다.
3. 생성 단계에서는 컴파일된 모듈을 덩어리로 결합한 후 각 덩어리를 별도의 파일로 변환하여 파일 목록에 출력합니다. 출력 내용을 결정한 후 구성에 따라 출력 경로와 파일 이름을 결정합니다. , 그리고 파일을 추가하세요. 콘텐츠는 파일 시스템에 기록됩니다
loader
webpack은 JS 및 JSON 파일만 이해할 수 있습니다. 로더는 본질적으로 다른 유형의 파일을 변환할 수 있는 변환기입니다.
Loader는 webpack 빌드 단계에서 종속 객체에 의해 생성된 모듈을 표준 js 콘텐츠로 변환합니다. 예를 들어 vue-loader는 vue 파일을 js 모듈로 변환하고, 이미지 글꼴은 url-loader를 통해 데이터 URL로 변환하는 것입니다.
module.rules에서 다양한 로더를 구성하여 다양한 파일을 구문 분석할 수 있습니다
plugin
플러그인은 기본적으로 적용 함수가 있는 클래스입니다class myPlugin { apply(compiler) {} }
이 적용 함수에는 매개변수 컴파일러가 있습니다. webpack 객체의 초기화 단계에서는 컴파일러 객체에서 후크를 호출하여 다양한 후크에 대한 콜백을 등록할 수 있습니다. 이러한 후크는 전체 컴파일 수명 주기 동안 실행됩니다. 따라서 개발자는 후크 콜백을 통해 특정 코드를 여기에 삽입하여 특정 기능을 달성할 수 있습니다.
예를 들어 stylelint 플러그인은 stylelint가 확인해야 하는 파일 형식과 파일 범위를 지정할 수 있습니다. HtmlWebpackPlugin은 패키지된 템플릿 파일을 생성하는 데 사용되며 MiniCssExtactPlugin은 모든 CSS를 독립적인 청크로 추출하고 stylelintplugin은 개발 단계에서 스타일 확인 기능을 제공할 수 있습니다. .
MiniCssExtractPlugin 브라우저의 경우 페이지 리소스를 요청할 때마다 최신 리소스를 가져오길 기대하는 반면, 리소스가 있을 때 캐시된 개체를 재사용할 수 있을 것으로 기대합니다. 변경되지 않았습니다. 이때, 파일명 + 파일 해시값 방식을 이용하면 파일명만으로 리소스가 업데이트 되었는지 구별할 수 있다. Webpack에는 생성된 파일에 대해 해시 계산 방법이 내장되어 있으며 출력 파일에 해시 필드를 추가할 수 있습니다.
Webpack에는 3개의 내장 해시가 있습니다
hash: 프로젝트가 빌드될 때마다 전체 프로젝트와 관련된 해시가 생성됩니다.
해시는 각 프로젝트의 콘텐츠를 기반으로 계산되므로 불필요한 해시 변경이 발생하기 쉽고 이는 버전 관리에 도움이 되지 않습니다. 일반적으로 해시를 직접 사용할 기회는 거의 없습니다.
content hash: 단일 파일의 콘텐츠와 관련됩니다. 지정된 파일의 내용이 변경되면 해시도 변경됩니다. 내용은 변경되지 않고 해시 값도 변경되지 않습니다.
Css 파일의 경우 일반적으로 MiniCssExtractPlugin을 사용하여 별도의 CSS 파일로 추출합니다.
이 시점에서 contenthash를 사용하여 표시하면 CSS 파일의 내용이 변경될 때 해시가 업데이트될 수 있습니다.
chunk hash: 웹팩 패키징으로 생성된 청크와 관련됩니다. 각 항목에는 서로 다른 해시가 있습니다.
일반적으로 출력 파일에는 청크해시를 사용합니다.
webpack이 패키징된 후에는 각 항목 파일과 해당 종속 항목이 결국 별도의 js 파일을 생성하게 되기 때문입니다.
이때 청크해시를 사용하면 패키지된 콘텐츠 전체의 업데이트 정확성을 보장할 수 있습니다.
확장: file-loader hash 일부 학생들은 다음과 같은 질문을 할 수 있습니다.
일부 이미지 및 글꼴 파일-로더 패키징을 처리할 때 [이름]_[hash:8].[ext]를 사용하는 경우를 종종 볼 수 있습니다
그러나 index.js와 같은 다른 프로젝트 파일이 변경되면 생성된 이미지 해시가 변경되지 않았습니다.
여기서 로더 자체에 의해 정의된 자리 표시자인 file-loader의 해시 필드는 webpack의 내장 해시 필드와 일치하지 않는다는 점에 유의해야 합니다.
여기서 해시는 md4와 같은 해시 알고리즘을 사용하여 파일 내용을 해시하는 것입니다.
파일 내용이 변경되지 않는 한 해시는 일관성을 유지합니다.
Vite는 주로 두 부분으로 구성됩니다
개발 환경
Vite는 브라우저를 사용하여 서버 측에서 가져오기를 구문 분석하고, 컴파일하고 요청 시 반환하므로 패키징 개념을 완전히 건너뛰고, 서버는 사용하기 쉽습니다(개발 중인 파일을 ESM 형식으로 변환하여 브라우저로 직접 보내는 것과 동일)
브라우저가 './comComponents/HelloWorld.vue'에서 import HelloWorld를 구문 분석할 때 요청을 보냅니다. 해당 리소스(ESM은 상대 경로 구문 분석 지원)에 대해 브라우저에서 직접 해당 파일을 다운로드하고 모듈 레코드로 구문 분석합니다(네트워크 패널을 열면 응답 데이터가 모두 ESM 유형 js임을 확인할 수 있습니다). ). 그런 다음 모듈에 메모리를 인스턴스화하고 할당하고 import 및export 문에 따라 모듈과 메모리 간의 매핑 관계를 설정합니다. 마지막으로 코드를 실행해 보세요.
vite는 koa 서버를 시작하여 브라우저의 ESM 요청을 가로채고, 요청 경로를 통해 디렉터리에서 해당 파일을 찾아 ESM 형식으로 처리한 후 클라이언트에 반환합니다.
Vite의 핫 로딩은 클라이언트와 서버 사이에 웹소켓 연결을 설정합니다. 코드가 수정된 후 서버는 클라이언트에게 수정된 모듈 코드를 요청하라는 메시지를 보냅니다. 핫 업데이트를 완료하려면 무엇이든 다시 요청해야 합니다. 뷰 파일이 변경됩니다. 해당 파일은 핫 업데이트 속도가 프로젝트 크기에 영향을 받지 않도록 합니다.
개발 환경은 esbuild를 사용하여 종속성에 대한 캐시를 사전 구축합니다. 첫 번째 시작은 느려지고 후속 시작은 캐시를 직접 읽습니다.
프로덕션 환경
은 롤업을 사용하여 코드를 빌드하고 다음을 제공합니다. 빌드 프로세스 최적화에 대한 지침입니다. 단점은 개발 환경과 프로덕션 환경이 일치하지 않을 수 있다는 것입니다.
Webpack의 핫 업데이트 원칙은 단순히 특정 종속성이 발생하면(예: a.js
)改变,就将这个依赖所处的 module
的更新,并将新的 module
发送给浏览器重新执行。每次热更新都会重新生成 bundle
. 파일 하나만 수정하더라도 이론적으로 핫 업데이트 속도는 점점 더 느려질 것입니다.
Vite는 브라우저를 사용하여 가져오기를 구문 분석하고 필요에 따라 컴파일하고 서버 측에 반환하며 완전히 건너뜁니다. 패키징의 개념에 따르면 서버는 언제든지 사용할 수 있으며 핫 업데이트는 클라이언트와 서버 사이에 웹 소켓 연결을 설정하는 것입니다. 코드가 수정된 후 서버는 수정된 모듈 코드를 요청하도록 클라이언트에 알리는 메시지를 보냅니다. 어떤 파일이 변경되든 핫 업데이트를 완료하려면 다시 요청해야 합니다. 이를 통해 핫 업데이트 속도가 프로젝트 크기에 영향을 받지 않습니다.
그래서 현재 Vite의 가장 큰 특징은 서비스가 시작된다는 것입니다. 빠르고 핫 업데이트가 빨라 개발자 경험을 최적화합니다. 프로덕션 환경의 최하위 계층이 롤업이므로 롤업은 확장성 및 기능 측면에서 소규모 프로젝트에 더 적합합니다. Vite를 개발 서버로 사용하고, 프로덕션 패키징에는 webpack을 사용할 수 있습니다.
2. 위의 종속 라이브러리는 비즈니스 코드에서 분리되는 것과 같습니다. 종속 라이브러리 자체의 버전이 변경되는 경우에만 다시 패키징되어 패키징 속도가 향상됩니다.
3. 로더에 oneOf를 사용할 수 있습니다
. 해당 로더가 일치하는 한 로더는 계속 실행되지 않습니다. 로더의 동기 실행을 병렬 실행으로 변환하려면 happyPack을 사용하세요. loader, css-loader, less-loader가 결합되어 실행됩니다.8.terserPlugin은 MiniCssExtractPlugin을 압축합니다. CSS
0 스크립트 구성 항목은 package.json 파일에 정의할 수 있으며, 이는 스크립트 실행을 위한 키와 값을 정의할 수 있습니다
1. node_modules/.bin
디렉터리에 대한 스크립트 소프트 링크 , node_modules/.bin
目录下,同时将./bin
加入当环境变量$PATH
中,所以如果在全局直接运行该命令会去全局目录里找,可能会找不到该命令就会报错。比如 npm run start,他是执行的webpack-dev-server带上参数
2、还有一种情况,就是单纯的执行脚本命令,比如 npm run build,实际运行的是 node build.js,即使用 node 执行 build.js 这个文件
ES6
CommonJS
代理模式:为对象提供一个代用品或占位符,以便控制对它的访问
例如实现图片懒加载的功能,先通过一张loading
图占位,然后通过异步的方式加载图片,等图片加载好了再把完成的图片加载到img
환경 변수 $PATH
에 ./bin
추가
디자인 패턴
에이전트 모드
loading
이미지 자리 표시자를 전달한 다음 이미지를 비동기식으로 로드하고, 이미지가 로드된 후 완성된 이미지를 img
태그에 로드Decorator 모드
데코레이터 모드의 정의: 프로그램이 실행 중일 때 객체 자체를 변경하지 않고 이 기간 동안 , 메소드는 객체에 동적으로 추가됩니다일반적으로 원래 메소드를 변경하지 않고 유지한 다음 기존 요구 사항을 충족하기 위해 원래 메소드에 다른 메소드를 마운트하는 데 사용됩니다. 🎜🎜typescript와 같은 데코레이터는 일반적인 데코레이터 패턴이며 vue🎜🎜🎜singleton 패턴🎜🎜🎜의 mixin은 클래스에 인스턴스가 하나만 있고 이에 액세스할 수 있는 전역 액세스 포인트를 제공합니다. 구현 방법은 먼저 인스턴스가 존재하는지 확인하고 존재하지 않으면 직접 생성하여 반환합니다. 이렇게 하면 클래스에 인스턴스 객체가 하나만 있는 것을 보장합니다🎜🎜예를 들어 ice stark의 경우 하위 애플리케이션은 한 번에 하나만 렌더링하도록 보장됩니다. 게시자로 간주될 수 있음), 관찰자 모드는 특정 대상에 의해 예약되는 반면 게시/구독 모드는 일정 센터에 의해 균일하게 조정되므로 구독자와 관찰자 모드의 게시자 간에 종속성이 있습니다. /subscribe 모드는 그렇지 않습니다. 🎜🎜2. 두 패턴 모두 느슨한 결합, 향상된 코드 관리 및 잠재적인 재사용을 위해 사용될 수 있습니다. 🎜🎜3. 관찰자 모드에서는 관찰자는 주체를 알고, 주체는 관찰자의 기록을 유지합니다. 그러나 게시-구독 모델에서는 게시자와 구독자가 서로의 존재를 인식하지 못합니다. 그들은 메시지 브로커를 통해서만 통신합니다🎜🎜4. 관찰자 모드는 대부분 동기식입니다. 예를 들어 이벤트가 트리거되면 주제는 관찰자 메서드를 호출합니다. 게시-구독 패턴은 대부분 비동기식입니다(메시지 대기열 사용) 🎜정규 표현식은 어떤 데이터 유형인가요?
는 객체입니다. let re = /ab+c/
는 let re = new RegExp('ab+c')
let re = /ab+c/
等价于let re = new RegExp('ab+c')
正则贪婪模式和非贪婪模式?
量词
*
:0或多次; ?
:0或1次; +
:1到多次; {m}
:出现m次; {m,}
:出现至少m次; {m, n}
:出现m到n次
贪婪模式
正则中,表示次数的量词默认是贪婪的,会尽可能匹配最大长度,比如a*
会从第一个匹配到a的时候向后匹配尽可能多的a,直到没有a为止。
非贪婪模式
在量词后面加?
就能变成非贪婪模式,非贪婪即找出长度最小且满足条件的
贪婪& 非贪婪特点
贪婪模式和非贪婪模式,都需要发生回溯才能完成相应的功能
独占模式
独占模式和贪婪模式很像,独占模式会尽可能多地去匹配,如果匹配失败就结束,不会进行回溯,这样的话就比较节省时间。
写法:量词后面使用+
优缺点:独占模式性能好,可以减少匹配的时间和 cpu 资源;但是某些情况下匹配不到,比如:
正则 | 文本 | 结果 | |
---|---|---|---|
贪婪模式 | a{1,3}ab | aaab | 匹配 |
非贪婪模式 | a{1,3}?ab | aaab | 匹配 |
独占模式 | a{1,3}+ab | aaab | 不匹配 |
a{1,3}+ab 去匹配 aaab 字符串,a{1,3}+ 会把前面三个 a 都用掉,并且不会回溯
常见正则匹配
操作符 | 说明 | 实例 | ||
---|---|---|---|---|
. | 表示任何单个字符 | |||
[ ] | 字符集,对单个字符给出范围 | [abc] 表示 a、b、c,[a-z]表示 a-z 的单个字符 | ||
[^ ] | 非字符集,对单个字符给出排除范围 | [^abc] 表示非a或b或c的单个字符 | ||
_ | 前一个字符零次或无限次扩展 | abc_ 表示 ab、abc、abcc、abccc 等 | ||
` | ` | 左右表达式的任意一个 | `abc | def`表示 abc、def |
$ | 匹配字符串结尾 | abc$ 表示 abc 且在一个字符串结尾 | ||
( ) | 分组标记内部只能使用 | (abc) 表示 abc,`(abc | def)`表示 abc、def | |
D | 非数字 | |||
d | 数字,等价于0-9 | |||
S | 可见字符 | |||
s | 空白字符(空格、换行、制表符等等) | |||
W | 非单词字符 | |||
w | 单词字符,等价于[a-z0-9A-Z_] | |||
匹配字符串开头 | ^abc 表示 abc 且在一个字符串的开头 | |||
{m,n} | 扩展前一个字符 m 到 n 次 | ab{1,2}c 表示 abc、abbc | ||
{m} | 扩展前一个字符 m 次 | ab{2}c 表示 abbc | ||
{m,} | 匹配前一个字符至少m 次 | |||
? | 前一个字符 0 次或 1 次扩展 | abc? | regulargreedy 모드와 동일합니다. 그리고 비 욕심 모드? | Quantifier |
a*
는 역방향으로 일치합니다. 첫 번째 경기부터 a까지 a가 하나도 남지 않을 때까지 가능한 한 많은 a를 시도합니다. 🎜🎜🎜Non-greedy 모드🎜🎜🎜Non-greedy 모드가 되려면 수량자 뒤에 ?
를 추가하세요. Non-greedy는 최소 길이를 찾아 조건을 충족한다는 의미입니다. 🎜🎜🎜Greedy & Non-greedy 특징🎜🎜 🎜그리디 모드와 비그리디 모드 모두 해당 기능을 완성하기 위해 🎜백트래킹🎜이 필요합니다. 🎜🎜🎜배타 모드🎜🎜🎜배타 모드는 그리디 모드와 매우 유사하며, 해당 기능이 충족되면 종료됩니다. 일치가 실패하면 역추적이 수행되지 않아 시간이 절약됩니다. 🎜🎜작성: 수량자 뒤에 +
를 사용하세요🎜🎜장점과 단점: 단독 모드는 성능이 좋고 일치 시간과 CPU 리소스를 줄일 수 있지만 다음과 같은 경우에는 일치를 달성할 수 없습니다. 🎜 | 일반 | 텍스트 | 결과 | 🎜||
---|---|---|---|---|---|
연산자 | 설명 | 인스턴스 | 🎜 | 🎜 | 🎜
---|---|---|---|---|
w 🎜🎜단어 문자 등 가격은 [a-z0-9A-Z_]🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜 | ||||