题目准备

基础题

https://juejin.im/post/5af8f00c51882567105fda7b
https://www.cnblogs.com/kevin2chen/p/6418327.html

event loop

task主要包含:setTimeout、setInterval、setImmediate、I/O、UI交互事件

获取H5页面打开时间

准备工作

  1. 一部测试手机(安卓,ios)
  2. 一部iPhone手机(可以是自己的手机)
  3. Aegisub(读音:/ˈiːdʒisʌb/)是一个免费、开源、跨平台的字幕编辑软件

测试手机

用来打开需要测试的h5页面,测试的时候需要考虑几种情况(安卓,ios,Wi-Fi,4G,有缓存,无缓存)。

主要是看点击按钮以后,从新webview显示第一帧到页面第一个元素可见的时间(不包括灰图或者loading)。

iPhone手机

iPhone进行60fps拍摄,开启方式:设置 → 相机 → 录制视频 → 1080p HD, 60fps,

经过实测,录制的视频为60fps, 精度在16 毫秒左右,对app本身性能无影响。

设置好以后录制测试手机打开h5页面的视频。

为了保证准确率建议录制5-10次去掉特殊情况取平均值。

Aegisub视频工具

把iPhone录制好的视频拖入Aegisub里面,按方向键,如图记录新开webview的时间和页面第一个元素可见时间,然后使用可见时间减去新开webview的时间即为页面打开时间。

题目准备_第1张图片
image.png

microtask主要包含:Promise、process.nextTick、MutaionObserver

css 权重

!important > 行内样式(比重1000) > id(比重100) > class/属性(比重10) > tag / 伪类(比重1);

css的百分比定位

  • 一个元素的border-radius定义的百分比值,参照物是这个元素自身的尺寸
  • margin和padding,其任意方向的百分比值,参照都是包含块的宽度。
  • 由放置背景图的区域尺寸,减去背景图的尺寸得到,可以为负值
  • font-size 参照是直接父元素的font-size
  • line-height参照是元素自身的font-size

react setstatus删除对象

this.setState((prevState, props) => {
    delete prevState.prop;
    return prevState;
});
this.setState({
a:'',null,undefind
});

浏览器渲染dom顺序

  • HTML解析出DOM Tree
  • CSS解析出Style Rules
  • 将二者关联生成Render Tree
  • Layout 根据Render Tree计算每个节点的信息
  • Painting 根据计算好的信息绘制整个页面

js中new一个对象的过程

优先级由高到低:小括号(xxx) ---> 属性访问. ---> new foo() ----> foo()

js 代码优化

  • if(!myValue)
  • var a = function(){} 方法执行完之后立马销毁
  • 请尽量避免使用全局变量

map 对象

var item = {};
size Object.Keys(items).length;
set items[key] = value;
remove

 if (this.has(key)) {
            delete items[key];
            return true;
        }
        return false;

has return key in items;
get return this.has(key)?items[key]:undefined;
clear items = {};
values

promise对象

repaint 和reflow

repaint主要是针对某一个DOM元素进行的重绘,reflow则是回流,针对整个页面的重排
触发repaint:
color的修改,如color=#ddd;
text-align的修改,如text-align=center;
a:hover也会造成重绘。
:hover引起的颜色等不导致页面回流的style变动。
等等太多,一时间写出来也太难想了。

触发reflow:
width/height/border/margin/padding的修改,如width=778px;
动画,:hover等伪类引起的元素表现改动,display=none等造成页面回流;
appendChild等DOM元素操作;
font类style的修改;
background的修改,注意着字面上可能以为是重绘,但是浏览器确实回流了,经过浏览器厂家的优化,部分background的修改只触发repaint,当然IE不用考虑;
scroll页面,这个不可避免;
resize页面,桌面版本的进行浏览器大小的缩放,移动端的话,还没玩过能拖动程序,resize程序窗口大小的多窗口操作系统。
读取元素的属性(这个无法理解,但是技术达人是这么说的,那就把它当做定理吧):读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE));

promise静态方法

Promise.resolve()
Promise.reject()
Promise.all()
Promise.race()

this 关键字

this是Javascript语言的一个关键字。它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。
完全取决于他的执行环境
this指的是,调用函数的那个对象

new 执行过程

创建一个空的对象
let p1 = new Object();
Object.create({})
设置原型链
p1.proto = SouthSu.prototype;

让 构造函数 的this 指向 p1 这个空对象

let funCall = SouthSu.call(p1);

判断 js 中的数据类型

  • typeof

  • instanceof
    其实 instanceof 主要的作用就是判断一个实例是否属于某种类型
    let person = function () {
    }
    let nicole = new person()
    nicole instanceof person

  • constructor [a.constructor,b.constructor]

  • Object.prototype.toString.call(a) === ‘[object String]’

数据类型

Object,Number,String, Boolean, Undefined,Null.
undefined,表示一个未知状态,声明了但是没有初始化的该变量.
null 表示尚未存在的对象,null 是一个有特殊意义的值。

parseInt(arg)将指定的字符串,转换成整数
parseFloat(arg)将指定的字符串,转换成浮点数
Number(arg)
String(arg)把给定的值(任意类型)转换成字符串;
Boolean(arg)把给定的值(任意类型)转换成 Boolean 型;

原型链,对象,构造函数之间的一些联系

每一个函数(类)都有属性protytype(原型)属性,属性值是一个对象;这个对象中存储了当前供实例调用的共有属性和方法;
在浏览器默认给原型开辟的堆内存中存在属性constructor;存储的是当前类本省;
每一个对象(实例)都有proto(原型链)属性,这个属性指向所属类的原型(不确认所属的类,都指向object.prototype)

function People(){}
var p = new People()
p.proto === People.prototype
People.proto === Function.prototype
People.prototype.proto === Object.prototype

//代码2
Function.prototype === Function.proto
Function.prototype === Object.proto
Function.prototype.proto === Object.prototype
Function instanceof Object

call,apply,bind

let arr1 = [1, 2, 19, 6];
//例子:求数组中的最值
console.log(Math.max.call(null, 1,2,19,6)); // 19
console.log(Math.max.call(null, arr1)); // NaN
console.log(Math.max.apply(null, arr1)); // 19 直接可以用arr1传递进去

而bind则是返回改变了上下文后的一个函数。

说说xss与csrf,怎么防止

xss:跨站脚本攻击,如果不过滤执行了js代码,可能导致cookie泄露等。防止:过滤

csrf:跨站请求伪造,挟制用户在当前已登录的Web应用程序上执行非本意的操作。防止:设置token、写操作用post、JSON API禁用CORS、禁用跨域请求、检查referrer

事件委托代码

// 给父层元素绑定事件
    document.getElementById('list').addEventListener('click', function (e) {
        // 兼容性处理
        var event = e || window.event;
        var target = event.target || event.srcElement;
        // 判断是否匹配目标元素
        if (target.nodeName.toLocaleLowerCase() === 'li') {
            console.log('the content is: ', target.innerHTML);
        }
    });

局限性
比如 focus、blur 之类的事件本身没有事件冒泡机制,所以无法委托;
mousemove、mouseout 这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,因此也是不适合于事件委托的;

闭包

把闭包简单理解成"定义在一个函数内部的函数"。
保存和保护函数内部的变量
另一个就是让这些变量的值始终保持在内存中。

因为 IE。IE 有 bug,IE 在我们使用完闭包之后,依然回收不了闭包里面引用的变量。

内容层面

  • 使用CDN
  • 单域名、多域名,单域名可以减少DNS查找次数,多域名可以增加浏览器并行下载数量,这需要权衡,一般同一个域下不要超过四个资源。
  • 避免重定向(分场景)
  • 避免404

网络层面

  • 利用缓存,可以参考另一篇文章手写文件服务器,说说前后端交互
  • 文件压缩(通过响应头Accept-Encoding: gzip, deflate, br告诉服务器你支持的压缩类型)
  • 按需加载,提取公共代码,tree-shaking等(都可以通过webpack来实现)
  • 减少cookie大小
  • 文件合并,通过css雪碧图合并图片
  • 文件预加载、图片懒加载

渲染层间

  • js放底部,css放顶部
  • 减少reflow(回流)和repaint(重绘)
  • 减少dom节点

代码层面

  • 缓存dom节点,减少节点查找,css选择器层级优化
  • 减少dom节点操作
  • 合理使用break、continue、return等,优化循环
  • 像react用到的事件委托、对象池等手段

跨域解决办法

浏览器的同源策略导致了跨域
不同域名,不同domain,不同端口
解决办法:

  1. nginx 反向代理(nginx 服务内部配置 Access-Control-Allow-Origin *)
  2. cors 前后端协作设置请求头部,Access-Control-Allow-Origin 等头部信息
  3. iframe 嵌套通讯,postmessage
    通过修改docment.domain来实现跨域
      该方法必须是在同主域,不同子域的情况下才生效
      比如:morningstar.com 和test.morningstar.com
  4. jsonp ,允许 script 加载第三方资源
  5. postMessage
    不同域之间的跨域请求 使用postMessage。postMessage是HTML5新增的方法

Array对象常用方法中:

不改变原数组:

1、 concat()
[].concat([1])
连接两个或多个数组
不改变原数组
返回被连接数组的一个副本
2、join()
[1,2,3].join('1')
把数组中所有元素放入一个字符串
不改变原数组
返回字符串
3、 slice()
[12,3,4,5,6].slice(1,2)
从第几个到第几个
从已有的数组中返回选定的元素
不改变原数组
返回一个新数组
4、 toString()
把数组转为字符串
不改变原数组
返回数组的字符串形式
改变原数组:

5、 pop()
删除数组最后一个元素,如果数组为空,则不改变数组,返回undefined
改变原数组
返回被删除的元素
6、 push()
向数组末尾添加一个或多个元素
改变原数组
返回新数组的长度
7、 reverse()
颠倒数组中元素的顺序
改变原数组
返回该数组
8、 shift()
把数组的第一个元素删除,若空数组,不进行任何操作,返回undefined
改变原数组
返回第一个元素的值
9、 sort()
对数组元素进行排序(ascii)
改变原数组
返回该数组
10、 splice()
从数组中添加/删除项目
改变原数组
返回被删除的元素
11、 unshift()
向数组的开头添加一个或多个元素
改变原数组
返回新数组的长度

基本的数据类型

5个简单数据类型(基本数据类型)+ 1个复杂数据类型
undefiend, number string null boolean + object
ES6 新增Symbol

深拷贝对象方法

  • 直接遍历
function copy (obj) {
   let newObj = {};
     for (let item in obj ){
       newObj[item] = obj
     }
     return newObj;
}
 
var copyObj = copy(obj);
  • ES6的Object.assign
    var copyObj = Object.assign({}, obj);
  • ES6扩展运算符:
    var copyObj = { ...obj }
  • 多层嵌套拷贝
    JSON.parse(JSON.stringify(XXXX))
  • immutable
const map1 = Map({ a: 1, b: 2, c: 3 })
const map2 = map1.set('b', 50)

React生命周期

题目准备_第2张图片
image.png
题目准备_第3张图片
image.png

https://zhuanlan.zhihu.com/p/35587283

React 16新特性

  • Error Boundary

  • 在React 16中,render方法支持直接返回string,number,boolean,null,portal,以及fragments(带有key属性的数组),这可以在一定程度上减少页面的DOM层级。

  • 使用createPortal将组件渲染到当前组件树之外

  • setState传入null时不会再触发更新

  • React.lazy() 和 Suspense

Loading...
}>
  • createRef
    父组件调用子组建方法

  • 新增两个新的生命周期

getDerivedStateFromProps
在render函数之前的所有函数(componentWillMount,componentWillReceiveProps,componentWillUpdate)都被getDerivedStateFromProps替代。
static getDerivedStateFromProps(props, state) 在组件创建时和更新时的render方法之前调用,它应该返回一个对象来更新状态,或者返回null来不更新任何内容。

getSnapshotBeforeUpdate() 被调用于render之后,可以读取但无法使用DOM的时候。它使您的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。

组件化思路

  • 合理的目录结构,代码资源管理更合理
  • 提高开发效率和代码质量
  • 低耦合,单一职责,可复用性,可维护性

一个组件不应对其它兄弟组件造成直接影响。
接口设计符合规范和大众习惯,尽量让别人用起来简单易上手,易上手是指更符合直觉。

react 优化

在 React 应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树。

  • 如要避免不必要的子组件的重渲染,你需要在所有可能的地方使用 PureComponent,或是手动实现 shouldComponentUpdate 方法。同时你可能会需要使用不可变的数据结构来使得你的组件更容易被优化。

  • 然而,使用 PureComponent 和 shouldComponentUpdate 时,需要保证该组件的整个子树的渲染输出都是由该组件的 props 所决定的。如果不符合这个情况,

postcss

常用插件说明以及postcss说明
https://www.w3cplus.com/css/taobao-2018-year.html
postcss 插件列表
postcss-import
postcss-url
postcss-aspect-ratio-mini
postcss-cssnext
autoprefixer
postcss-px-to-viewport
postcss-write-svg
cssnano
postcss-viewport-units

webpack相关

webpack4的新版本有什么新特性

  • mode 属性 改变是webpack需要设置mode属性,可以是 development 或 production。
"scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
    }
  • webpack4删除了CommonsChunkPlugin插件,它使用内置API optimization.splitChunks 和 optimization.runtimeChunk,这意味着webpack会默认为你生成共享的代码块。其它插件变化如下:
  • 开箱即用WebAssembly
  • 0CJS webpack4不再强制需要 webpack.config.js 作为打包的入口配置文件了,它默认的入口为'./src/'和默认出口'./dist',

webpack4常用插件

  • HtmlWebpackPlugin //基于EJS模板生成html
  • CleanWebpackPlugin //删除旧的生成文件
  • loader:[
    style-loader css-loader less less-loader
    ]

其他

柯里化实现代码

只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。
你可以一次性地调用 curry 函数,也可以每次只传一个参数分多次调用。

const curry = (fn, ...arg) => {
    let all = arg || [],
    length = fn.length;
    return (...rest) => {
        let _args = all;
        _args.push(...rest);
        if (rest.length === 0) {
            all=[];
            return fn.apply(this, _args);
        } else {
            return curry.call(this, fn, ..._args);
            }
    }
}

和vuex的区别对比

vuex的流向:view——>commit——>mutations——>state变化——>view变化(同步操作)
view——>dispatch——>actions——>mutations——>state变化——>view变化(异步操作)

redux的流向:view——>actions——>reducer——>state变化——>view变化(同步异步一样)

react可以很细粒度的监控渲染(给setState传递回掉函数),而vue通过 this.$next 来监控,很难知道哪些数据变更导致的渲染。

babel工作原理

新标准引入的新的原生对象,部分原生对象新增的原型方法,新增的API等(如Proxy、Set等),这些babel是不会转译的。需要用户自行引入polyfill来解决

ES6代码输入 ==》 babylon进行解析 ==》 得到AST
==》 plugin用babel-traverse对AST树进行遍历转译 ==》 得到新的AST树
==》 用babel-generator通过AST树生成ES5代码

babel 转译语法需要一些plugin
如 react,es2015,stage-0,stage-1等等
其中的 es2015 表示 babel会加载 es6 相关的编译模块,然后 stage-0 表示的是什么呢?
stage 系列集合了一些对 es7 的草案支持的插件,由于是草案,所以作为插件的形式提供。

stage 是向下兼容 0>1>2>3>4 所包含的插件数量依次减少

stage-0

包含stage-1, stage-2以及stage-3的所有功能以及支持下列两个插件
transform-do-expressions 插件支持if/else表达式
transform-function-bind插件提供双冒号::操作符快速切换上下文

stage-2 包含stage-3的所有功能以及支持下列两个插件

syntax-trailing-function-commas
transform-object-rest-spread 数组的解构赋值的一个扩展

stage3

支持大名鼎鼎的async和await

es6

let const
解构赋值
模板字符串
箭头函数
展开运算符
类的编译
promise
数组的常见方法
some,every,filter es5
find findindex es6
reduce
array.from
对象的常见方法
object.assign

reactnative 优化

ios的设备是每秒60帧,Javascript线程对于一个帧没有响应,则被认为删除这个帧
主要场景响应触摸,导航的切换。
性能问题来源:

  • Console.log 语句 会包含调试库redux-logger,
  • Development mode(dev=true)
  • 将基于 Javascript的动画转变为基于main thread的动画 使用LayoutAnimation,利用了核心动画,不会受到JS线程和主线程丢帧的影响

hybird 优化

  • 客户端代理数据请求
    在客户端初始化WebView的同时,直接由native开始网络请求数据;
    当页面初始化完成后,向native获取其代理请求的数据。
    此方法虽然不能减小WebView初始化时间,但数据请求和WebView初始化可以并行进行,总体的页面加载时间就缩短了;缩短总体的页面加载时间:

  • 详情页加载优化- localStorage ;

  • 头部,toast,loading可以交由app完成

  • 随时初始化好一个WebView待用。

webpack 节点

对于loader,它就是一个转换器,将A文件进行编译形成B文件,这里操作的是文件,比如将A.scss或A.less转变为B.css,单纯的文件转换过程;

对于plugin,它就是一个扩展器,它丰富了wepack本身,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作.

webpack 节点

run:开始编译
make:从entry开始递归分析依赖并对依赖进行build
build-moodule:使用loader加载文件并build模块
normal-module-loader:对loader加载的文件用acorn编译,生成抽象语法树AST
program:开始对AST进行遍历,当遇到require时触发call require事件
seal:所有依赖build完成,开始对chunk进行优化(抽取公共模块、加hash等)
optimize-chunk-assets:压缩代码
emit:把各个chunk输出到结果文件

浏览器访问链接

详细版:
1、浏览器会开启一个线程来处理这个请求,对 URL 分析判断如果是 http 协议就按照 Web 方式来处理;
2、调用浏览器内核中的对应方法,比如 WebView 中的 loadUrl 方法;
3、通过DNS解析获取网址的IP地址,设置 UA 等信息发出第二个GET请求;
4、进行HTTP协议会话,客户端发送报头(请求报头);
5、进入到web服务器上的 Web Server,如 Apache、Tomcat、Node.JS 等服务器;
6、进入部署好的后端应用,如 PHP、Java、JavaScript、Python 等,找到对应的请求处理;
7、处理结束回馈报头,此处如果浏览器访问过,缓存上有对应资源,会与服务器最后修改时间对比,一致则返回304;
8、浏览器开始下载html文档(响应报头,状态码200),同时使用缓存;
9、文档树建立,根据标记请求所需指定MIME类型的文件(比如css、js),同时设置了cookie;
10、页面开始渲染DOM,JS根据DOM API操作DOM,执行事件绑定等,页面显示完成。

koa&& express 区别

koa && express 实现方式和基本原理

两者创建一个基础的 Web 服务都非常简单,写法也基本相同,最大的区别是路由处理 Express 是自身集成的,而 Koa 需要引入中间件。

Express 采用 callback 来处理异步,Koa v1 采用 generator,Koa v2 采用 async/await。
下面分别对 js 当中 callback、promise、generator、async/await 这四种异步流程控制进行了对比,
generator 和 async/await 使用同步的写法来处理异步,明显好于 callback 和 promise,async/await 在语义化上又要比 generator 更强。

koa 源码非常精简,只有四个文件:

application.js:Application(或Koa)负责管理中间件,以及处理请求
context.js:Context维护了一个请求的上下文环境
使用了 delegates 模块来实现属性访问的代理。简单来说,通过 delegate(proto, 'response') ,当访问 proto 的代理属性的时候,实际上是在访问 proto.response 的对应属性

request.js:Request对req做了抽象和封装
response.js:Response对res做了抽象和封装

mvvm实现原理

angular

DOM事件,譬如用户输入文本,点击按钮等。( ng-click )
XHR响应事件 ( location )
Timer事件( timeout,interval )
执行 digest()或apply()

Virtual DOM

Observer

利用Obeject.defineProperty()来监听属性变动
那么将需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter
监听数据和数据变化通知订阅者的功能

Compile

解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。
跟节点el转换成文档碎片fragment进行解析编译操作,解析完成,再将fragment添加回原来的真实dom节点中

Watcher

订阅者作为Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。

你可能感兴趣的:(题目准备)