TiffanysBear


  • Home

  • Tags

  • Categories

  • Archives

  • Vue

  • React

react-router学习笔记

Posted on 2019-12-03 | In React
Words count in article: 2.8k | Reading time ≈ 11

react-router学习笔记
author: @TiffanysBear

基本介绍

React Router 是完整的 React 路由解决方案

React Router 保持 UI 与 URL 同步。它拥有简单的 API 与强大的功能例如代码缓冲加载、动态路由匹配、以及建立正确的位置过渡处理。

基础部分

路由配置

index路由配置:添加首页,设置默认页面,使用 IndexRoute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { IndexRoute } from 'react-router'

const Dashboard = React.createClass({
render() {
return <div>Welcome to the app!</div>
}
})

React.render((
<Router>
<Route path="/" component={App}>
{/* 当 url 为/时渲染 Dashboard */}
<IndexRoute component={Dashboard} />
<Route path="about" component={About} />
<Route path="inbox" component={Inbox}>
<Route path="messages/:id" component={Message} />
</Route>
</Route>
</Router>
), document.body)
Read more »

【转】Mobx React  最佳实践

Posted on 2019-10-23 | In React
Words count in article: 1.1k | Reading time ≈ 4

【转】Mobx React  最佳实践
转载自 https://juejin.im/post/5a3b1a88f265da431440dc4a

在这一篇文章里,将展示一些使用了mobx的React的最佳实践方式,并按照一条一条的规则来展示。在你遇到问题的时候,可以依照着这些规则来解决。
这篇文章要求你对于mobx的stores有基本的理解,如果没有的话请先阅读官方文档。

Read more »

TypeScript学习笔记

Posted on 2019-10-20 | In TypeScript
Words count in article: 1.6k | Reading time ≈ 7

TypeScript学习笔记
author: @TiffanysBear

1、类型注解
2、接口interface:使用interface可以申明一个类型
3、类

  • 创建类时,在构造函数的参数上使用public等同于创建了同名的成员变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Student {
fullName: string;
constructor(public firstName, public middleInitial, public lastName) {
this.fullName = firstName + " " + middleInitial + " " + lastName;
}
}
// 编译后
var Student = /** @class */ (function () {
function Student(firstName, middleInitial, lastName) {
this.firstName = firstName;
this.middleInitial = middleInitial;
this.lastName = lastName;
this.fullName = firstName + " " + middleInitial + " " + lastName;
}
return Student;
}());
Read more »

前端面试题

Posted on 2019-09-09 | In javaScript
Words count in article: 1.1k | Reading time ≈ 3

前端面试题
author: @TiffanysBear

2年工作经验出去接受社会的毒打,参与的前端社招的公司和题目的记录如下,后续可能还会有增加,先暂时记录这么多:

头条

一面:
在一面之前先是做题,做题时间为40分钟,主要的笔试题和面试中涉及的部分包括以下:

  1. 宽度自适应,未知高度元素的水平垂直居中,字体水平垂直居中
  2. arguments是数组吗?怎么转换数组
  3. promise、await、setTimeout的执行顺序问题
  4. es6块级作用域、箭头函数
  5. 隐式转换问题
  6. 实现一个throttle
  7. 实现一个函数bind,bind具体使用场景
  8. 算法:求一个数组中n个数和为sum
  9. node中的事件循环和浏览器中事件循环有什么不同
  10. 宏任务和微任务具体有哪些
Read more »

FIS 插件机制

Posted on 2019-08-26 | In 插件
Words count in article: 2.6k | Reading time ≈ 10

FIS 插件机制
author: @TiffanysBear

当我们使用 FIS 插件的时候,有没有想过自己也开发一个基于 FIS 的插件,参与 FIS 打包编译的整个流程;那么问题就来了:

  • FIS 的编译过程运行原理是怎样的呢?
  • FIS 编译打包的过程有哪些?
  • 怎么参与FIS 的打包编译过程?
  • 怎么实现一个基于FIS的插件?
  • FIS 是怎么引入自定义插件的?

基于以下的问题,从原理再进行慢慢分析,了解 FIS 编译的基本流程和原理,以及如何自己自定义一个 FIS 插件。

编译过程运行原理

fis的编译过程可以分为两个阶段: 单文件编译 和 打包。处理流程如下图,图片来自 FIS 官网:

Read more »

重新理解前端系列 — AMD、CMD

Posted on 2019-08-21 | In JavaScript
Words count in article: 2.2k | Reading time ≈ 10

重新理解前端系列 — AMD、CMD
author: @TiffanysBear

本文主要是针对之前一些熟悉的前端概念,再次回顾的时候,结合自己的开发经验和使用,进行再次理解。经过了开发和线上使用之后,会有更为深刻的印象。对比requirejs源码分析,实现一个模块加载器,需要考虑哪些问题。

起源

其实对于AMD和CMD的不同,之前一直是拘泥在使用上的不同。没有深刻的认识为什么会有不同,其实主要是因为浏览器端和 Node 端不同性能特点和瓶颈带来的不同。

早期的js模块化主要用于浏览器端,主要的需求和瓶颈在于带宽,需要将js从服务端下载下来,从而带来的网络性能开销,因此主要是满足对于作用域、按需加载的需求。因此AMD(异步模块定义)的出现,适合浏览器端环境。

而后出现Node之后,主要的性能开销不再是网络性能,磁盘的读写和开销可以忽略不计;CMD的出现更符合Node 对于CommonJS的定义和理解,在运行时进行加载,引入时只是产生引用指向关系。

因此两者产生了不同的使用特点,在出现循环引用时,就产生了不同的现象。以下是针对 requirejs 源码部分的解读。如果有问题,欢迎提问纠正。

1、动态加载一个js模块的方法,怎么保证异步和回调的执行

一先开始是需要判断环境,浏览器环境和webworker环境;如果是浏览器环境,通过document.createElement 创建script标签,使用async属性使js能进行异步加载, IE等不兼容async字段的,通过监听 load 、 onreadystatechange 事件执行回调,监听脚本加载完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
req.createNode = function (config, moduleName, url) {
var node = config.xhtml ?
document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
document.createElement('script');
node.type = config.scriptType || 'text/javascript';
node.charset = 'utf-8';
node.async = true; //创建script标签添加了async属性
return node;
};
req.load = function (context, moduleName, url) { //用来进行js模块加载的方法
var config = (context && context.config) || {},
node;
if (isBrowser) { //在浏览器中加载js文件

node = req.createNode(config, moduleName, url); //创建一个script标签

node.setAttribute('data-requirecontext', context.contextName); //requirecontext默认为'_'
node.setAttribute('data-requiremodule', moduleName); //当前模块名

if (node.attachEvent &&
!(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
!isOpera) {

useInteractive = true;

node.attachEvent('onreadystatechange', context.onScriptLoad);
} else {
node.addEventListener('load', context.onScriptLoad, false);
node.addEventListener('error', context.onScriptError, false);
}
node.src = url;

if (config.onNodeCreated) { //script标签创建时的回调
config.onNodeCreated(node, config, moduleName, url);
}

currentlyAddingScript = node;
if (baseElement) { //将script标签添加到页面中
head.insertBefore(node, baseElement);
} else {
head.appendChild(node);
}
currentlyAddingScript = null;

return node;
} else if (isWebWorker) { //在webWorker环境中
try {
setTimeout(function () { }, 0);
importScripts(url); //webWorker中使用importScripts来加载脚本

context.completeLoad(moduleName);
} catch (e) { //加载失败
context.onError(makeError('importscripts',
'importScripts failed for ' +
moduleName + ' at ' + url,
e,
[moduleName]));
}
}
};

2、怎么判断去加载js,怎么保证加载的顺序

通过 setTimeout 放入下一个队列中,保证加载顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//通过setTimeout的方式加载依赖,放入下一个队列,保证加载顺序
context.nextTick(function () {
//Some defines could have been added since the
//require call, collect them.
intakeDefines();

requireMod = getModule(makeModuleMap(null, relMap));

//Store if map config should be applied to this require
//call for dependencies.
requireMod.skipMap = options.skipMap;

requireMod.init(deps, callback, errback, {
enabled: true
});

checkLoaded();
});

3、require中的js文件是怎么判断已经loaded,怎么保证加载数据的数量是正确的?

依赖数量,是通过 depCount 来计算的,通过循环遍历,统计具体的依赖数量;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// ...
enable: function () {
enabledRegistry[this.map.id] = this;
this.enabled = true;

//Set flag mentioning that the module is enabling,
//so that immediate calls to the defined callbacks
//for dependencies do not trigger inadvertent load
//with the depCount still being zero.
this.enabling = true;

//enable每一个依赖
each(this.depMaps, bind(this, function (depMap, i) {
var id, mod, handler;

if (typeof depMap === 'string') {
//Dependency needs to be converted to a depMap
//and wired up to this module.
depMap = makeModuleMap(depMap,
(this.map.isDefine ? this.map : this.map.parentMap),
false,
!this.skipMap);
this.depMaps[i] = depMap; //获取的依赖映射

handler = getOwn(handlers, depMap.id);

if (handler) {
this.depExports[i] = handler(this);
return;
}

this.depCount += 1; //依赖项+1

on(depMap, 'defined', bind(this, function (depExports) {
if (this.undefed) {
return;
}
this.defineDep(i, depExports); //加载完毕的依赖模块放入depExports中,通过apply方式传入require定义的函数中
this.check();
})); //绑定defined事件,同时将dep添加到registry中

if (this.errback) {
on(depMap, 'error', bind(this, this.errback));
} else if (this.events.error) {
// No direct errback on this module, but something
// else is listening for errors, so be sure to
// propagate the error correctly.
on(depMap, 'error', bind(this, function (err) {
this.emit('error', err);
}));
}
}

id = depMap.id;
mod = registry[id];

//跳过一些特殊模块,比如:'require', 'exports', 'module'
//Also, don't call enable if it is already enabled,
//important in circular dependency cases.
if (!hasProp(handlers, id) && mod && !mod.enabled) {
context.enable(depMap, this); //加载依赖
}
}));

//Enable each plugin that is used in
//a dependency
eachProp(this.pluginMaps, bind(this, function (pluginMap) {
var mod = getOwn(registry, pluginMap.id);
if (mod && !mod.enabled) {
context.enable(pluginMap, this);
}
}));

this.enabling = false;

this.check();
},

判断单个文件加载成功,是通过 checkLoaded 每间隔 50s 做一次轮询进行判断,变量 inCheckLoaded 作为标识;下面是 checkLoaded 函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
function checkLoaded() {
var err, usingPathFallback,
waitInterval = config.waitSeconds * 1000,
//It is possible to disable the wait interval by using waitSeconds of 0.
expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
noLoads = [],
reqCalls = [],
stillLoading = false,
needCycleCheck = true;

//Do not bother if this call was a result of a cycle break.
if (inCheckLoaded) {
return;
}

inCheckLoaded = true;

//Figure out the state of all the modules.
eachProp(enabledRegistry, function (mod) {
var map = mod.map,
modId = map.id;

//Skip things that are not enabled or in error state.
if (!mod.enabled) {
return;
}

if (!map.isDefine) {
reqCalls.push(mod);
}

if (!mod.error) {
//If the module should be executed, and it has not
//been inited and time is up, remember it.
if (!mod.inited && expired) {
if (hasPathFallback(modId)) {
usingPathFallback = true;
stillLoading = true;
} else {
noLoads.push(modId);
removeScript(modId);
}
} else if (!mod.inited && mod.fetched && map.isDefine) {
stillLoading = true;
if (!map.prefix) {
//No reason to keep looking for unfinished
//loading. If the only stillLoading is a
//plugin resource though, keep going,
//because it may be that a plugin resource
//is waiting on a non-plugin cycle.
return (needCycleCheck = false);
}
}
}
});

if (expired && noLoads.length) {
//If wait time expired, throw error of unloaded modules.
err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
err.contextName = context.contextName;
return onError(err);
}

//Not expired, check for a cycle.
if (needCycleCheck) {
each(reqCalls, function (mod) {
breakCycle(mod, {}, {});
});
}

//If still waiting on loads, and the waiting load is something
//other than a plugin resource, or there are still outstanding
//scripts, then just try back later.
if ((!expired || usingPathFallback) && stillLoading) {
//Something is still waiting to load. Wait for it, but only
//if a timeout is not already in effect.
if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
checkLoadedTimeoutId = setTimeout(function () {
checkLoadedTimeoutId = 0;
checkLoaded();
}, 50);
}
}

inCheckLoaded = false;
}

4、如果有循环引用,怎么判断出的,怎么解决的

这部分暂且还有点疑惑,先mark一下,之后再理解;

看到有个 breakCycle 函数,执行条件是 needCycleCheck 为 true,但是当 !mod.inited && mod.fetched && map.isDefine 模块未被初始化完成,但是已经获取过定义过之后,且 在 map.prefix 有前缀,会启动 breakCycle 检查;至于为什么要这么做,只能猜测是为了到模块require时循环引用打破轮询查询加载状态等待的问题,现在先留一个疑问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function breakCycle(mod, traced, processed) {
var id = mod.map.id;

if (mod.error) {
mod.emit('error', mod.error);
} else {
traced[id] = true;
each(mod.depMaps, function (depMap, i) {
var depId = depMap.id,
dep = getOwn(registry, depId);

//Only force things that have not completed
//being defined, so still in the registry,
//and only if it has not been matched up
//in the module already.
if (dep && !mod.depMatched[i] && !processed[depId]) {
if (getOwn(traced, depId)) {
mod.defineDep(i, defined[depId]);
mod.check(); //pass false?
} else {
breakCycle(dep, traced, processed);
}
}
});
processed[id] = true;
}
}

但是在CommonJs中时,存在依赖的情况下,因为存在的只是引用,代码执行是在实际调用时才发生,在文件的开头和结尾也会有变量标识是否加载完成。一旦某个模块出现循环依赖加载
,就只输出已经执行到的部分,还未执行的部分不会输出。

在ES6模块加载的循环加载情况下,ES6是动态引用的,不存在缓存值问题,而且模块里面的变量绑定所在的模块;不关心是否发生了循环加载,只是生成一个指向被加载模块的引用,需要开发者自己来保证真正取值的时候能够取到值。

Vue.js中watch的高级用法

Posted on 2019-08-21 | In Vue
Words count in article: 1.2k | Reading time ≈ 5

Vue.js中watch的高级用法
转载自 https://juejin.im/post/5ae91fa76fb9a07aa7677543
author: Dunizb

在 Vue.js 的学习中,看到这篇文章,转载记录一下用作备忘。

假设有如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div>
<p>FullName: {{fullName}}</p>
<p>FirstName: <input type="text" v-model="firstName"></p>
</div>

new Vue({
el: '#root',
data: {
firstName: 'Dawei',
lastName: 'Lou',
fullName: ''
},
watch: {
firstName(newName, oldName) {
this.fullName = newName + ' ' + this.lastName;
}
}
})

复制代码上面的代码的效果是,当我们输入firstName后,wacth监听每次修改变化的新值,然后计算输出fullName。

handler方法和immediate属性

这里 watch 的一个特点是,最初绑定的时候是不会执行的,要等到 firstName 改变时才执行监听计算。那我们想要一开始就让他最初绑定的时候就执行改怎么办呢?我们需要修改一下我们的 watch 写法,修改过后的 watch 代码如下:

1
2
3
4
5
6
7
8
9
watch: {
firstName: {
handler(newName, oldName) {
this.fullName = newName + ' ' + this.lastName;
},
// 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法
immediate: true
}
}
Read more »

从0到1发布一个npm包

Posted on 2019-08-15 | In JavaScript
Words count in article: 2.3k | Reading time ≈ 9

从0到1发布一个npm包
author: @TiffanysBear

最近在项目业务中有遇到一些问题,一些通用的方法或者封装的模块在PC、WAP甚至是APP中都需要使用,但是对于业务的PC、WAP、APP往往是不同的业务、不同的代码库中,尽管已经将公用的组件和方法抽离到各自公共common中,但是各个大业务大方向上的公用封装依然不能满足需求。

比如一个计算文档类型大小的方法,可能都同时存在于各个业务的common中,假设是有3处代码库中均有;如果此时的需求是将文档类型或者大小的方法进行一些修改,增加一种文档类型或者减少一种文档类型,那咱们是否是需要去共同修改上面的3处方法。这样做,很不利于代码的维护,浪费人力,增加了代码工作量。

那么,如何做到管理一些公共依赖的基础模块代码呢?这时候,封装发布一个npm包进行统一管理就是一个很好的办法了。

先po一下我在写这篇文章时,根据以下的步骤发布的一个简单封装的npm包以及github地址,大家可以先看:

npm包:page-performance-monitor
github地址:page-performance-monitor,欢迎 star、issue

下面,就从0开始讲起,如何从0到1发布一个npm包。先介绍一下什么是npm~

npm

npm 是JavaScript 世界的包管理工具,并且是Node.js 平台的默认包管理工具。通过npm 可以安装、共享、分发代码,管理项目依赖关系。

官网地址

比如有一些非常通用的公用方法,抽象封装,剔除一些冗余的业务需求,可以封装在一个npm包中,提供给相应的多个业务去使用。

那么接下来就列举一下封装一个简单的封装步骤;

发布步骤

以我之前的博客中列举的页面性能监控工具performance为例,具体的performance介绍可以点击链接,做一个简单的封装,满足基本的业务上的打点统计需求即可;后面也会讲到后续如何去封装一个高质量的npm包,比如加上一些example、测试test、完善README.md等,逐步去完善。大概是有以下几个步骤:

1、新建项目,准备需要发布的代码
2、准备package.json
3、注册npm账号、并登录
4、发布

其实发布的过程并不难,要发布一个好的质量高的npm包往往是取决于要封装的代码、以及对代码单测覆盖、demo案例、README介绍等

准备项目:

开始准备的步骤,从一个最基础的项目新建开始,都是在Mac的Linux环境上进行:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 新建项目文件夹
 mkdir page-performance
 
 // 初始化npm,初始化package.json
 npm init
 
 // 准备好封装代码
 // 一般源码是放在src,通过其他打包工具生成的一般是在dist目录或者build目录
 mkdir src
 
 // 可以将自己需要的代码往src中添加了
 // 假设我们只需要发布一个index.js就好
// ......

发布一个最简单的npm包:

1、先去官网注册一个账号,填写好账号、密码、邮箱
2、然后登录npm账号 npm login,如果你们公司有自己的默认npm仓库或者使用的淘宝镜像,注意需要指定一下仓库地址;npm login --registry=https://registry.npmjs.org

1
2
3
4
# 会依次让你输入用户名、密码、和邮箱
Username:
Password:
Email: (this IS public)

3、发布包 npm publish --registry=https://registry.npmjs.org

会提示+ page-performance-monitor@1.0.0 你的包名字和版本,那么说明就发布好了。

我在发布的时候遇到了两个小问题,记录一下,如果你们也有相同的问题,可以使用下面的解决办法:
1). 提示 publish Failed PUT 403

you must verify your email before publishing a new package: https://www.npmjs.com/email-edit : page-performance-monitor

之前登录的邮箱需要验证,去注册邮箱中找到npm发的邮件,点击验证一下就行.

2)第二个问题是:You do not have permission to publish “page-performance”. Are you logged in as the correct user? : page-performance

提示是说你没有权限发布这个包,其实是因为你的这个包名字和已有的重复了,需要在 package.json 里面换一个包名就行。

到这里,一个简单的npm包就封装好了,如何确认自己的包确认好了呢?去官网的搜索框输入你的包名搜一下,找到你的就ok啦~

到这步,你就会发布一个简单的npm包啦,如果只是一个很小的需求的化,就完全够用了;但是如果想要发布一个质量好有各种小标签logo的,那么就需要如下的步骤进行一下优化。

优化npm包:

Read more »

页面性能监测之performance

Posted on 2019-08-14 | In JavaScript
Words count in article: 2k | Reading time ≈ 7

页面性能监测之performance
author: @TiffanysBear

最近,需要对业务上的一些性能做一些优化,比如降低首屏时间、减少核心按钮可操作时间等的一些操作;在这之前,需要建立的就是数据监控的准线,也就是说一开始的页面首屏数据是怎样的,优化之后的数据是怎样,需要有一个对比效果。此时,performance 这个API就非常合适了。

performance

Performance 接口可以获取到当前页面中与性能相关的信息。它是 High Resolution Time API 的一部分,同时也融合了 Performance Timeline API、Navigation Timing API、 User Timing API 和 Resource Timing API。

该类型的对象可以通过调用只读属性 Window.performance 来获得。

参考链接 https://developer.mozilla.org/zh-CN/docs/Web/API/Performance

performance.timing对象

performance对象是全局的,它的timing属性是一个对象,它包含了各种与浏览器性能有关的时间数据,提供浏览器处理网页各个阶段的耗时。偷一个图~

performance.timing对象包含下列属性(全部只读):

  • navigationStart:当前浏览器窗口的前一个网页关闭,发生unload事件时的Unix毫秒时间戳。如果没有前一个网页,则等于fetchStart属性。

  • unloadEventStart:如果前一个网页与当前网页属于同一个域名,则返回前一个网页的unload事件发生时的Unix毫秒时间戳。如果没有前一个网页,或者之前的网页跳转不是在同一个域名内,则返回值为0。

  • unloadEventEnd:如果前一个网页与当前网页属于同一个域名,则返回前一个网页unload事件的回调函数结束时的Unix毫秒时间戳。如果没有前一个网页,或者之前的网页跳转不是在同一个域名内,则返回值为0。

  • redirectStart:返回第一个HTTP跳转开始时的Unix毫秒时间戳。如果没有跳转,或者不是同一个域名内部的跳转,则返回值为0。

  • redirectEnd:返回最后一个HTTP跳转结束时(即跳转回应的最后一个字节接受完成时)的Unix毫秒时间戳。如果没有跳转,或者不是同一个域名内部的跳转,则返回值为0。

  • fetchStart:返回浏览器准备使用HTTP请求读取文档时的Unix毫秒时间戳。该事件在网页查询本地缓存之前发生。

  • domainLookupStart:返回域名查询开始时的Unix毫秒时间戳。如果使用持久连接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值。

  • domainLookupEnd:返回域名查询结束时的Unix毫秒时间戳。如果使用持久连接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值。

  • connectStart:返回HTTP请求开始向服务器发送时的Unix毫秒时间戳。如果使用持久连接(persistent connection),则返回值等同于fetchStart属性的值。

  • connectEnd:返回浏览器与服务器之间的连接建立时的Unix毫秒时间戳。如果建立的是持久连接,则返回值等同于fetchStart属性的值。连接建立指的是所有握手和认证过程全部结束。

  • secureConnectionStart:返回浏览器与服务器开始安全链接的握手时的Unix毫秒时间戳。如果当前网页不要求安全连接,则返回0。

  • requestStart:返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的Unix毫秒时间戳。

  • responseStart:返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的Unix毫秒时间戳。

  • responseEnd:返回浏览器从服务器收到(或从本地缓存读取)最后一个字节时(如果在此之前HTTP连接已经关闭,则返回关闭时)的Unix毫秒时间戳。

  • domLoading:返回当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的readystatechange事件触发时)的Unix毫秒时间戳。

  • domInteractive:返回当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的Unix毫秒时间戳。

  • domContentLoadedEventStart:返回当前网页DOMContentLoaded事件发生时(即DOM结构解析完毕、所有脚本开始运行时)的Unix毫秒时间戳。

  • domContentLoadedEventEnd:返回当前网页所有需要执行的脚本执行完成时的Unix毫秒时间戳。

  • domComplete:返回当前网页DOM结构生成时(即Document.readyState属性变为“complete”,以及相应的readystatechange事件发生时)的Unix毫秒时间戳。

  • loadEventStart:返回当前网页load事件的回调函数开始时的Unix毫秒时间戳。如果该事件还没有发生,返回0。

  • loadEventEnd:返回当前网页load事件的回调函数运行结束时的Unix毫秒时间戳。如果该事件还没有发生,返回0。

Read more »

一些值得思考的前端面试题

Posted on 2019-08-08 | In Interview
Words count in article: 1.4k | Reading time ≈ 5

一些值得思考的前端面试题
还在继续补充中……
author: @TiffanysBear

ALL

  1. 在nodejs开发的时候 处理过什么windows和mac的平台兼容性问题

    • 兼容环境变量设置
    • windows不支持 & ,并行执行npm-script用npm-run-all或者concurrently
    • 异步同步化:util.promisify + async/await
    • fs.readFileSync,用fs-extra去代替
    • 拼接路径要用path.join,Unix系是/,Windows是\
    • ……
  2. 设计一个方案,在浏览器中点击一个button,然后能在你的前端项目源码文件中增加一个index.js文件,如何实现?提供思路

  3. 用nodejs,将base64转化成png文件,或者将png文件转化为base64

  4. 如果你用nodejs实现的爬虫服务器的IP被指定网站封了,如何解封?

  5. 请设计一个方案:有a、b、c三个npm插件,它们会经常更新,在前端项目npm run start启动后,要求a、b、c三个npm插件自动更新到最新版本

  6. 大文件转存问题:服务器A有一个1000G的文件, 需要通过服务端B转发到服务端C,但是服务器B内存只有1个g, 怎么去实现这个大文件转存

  7. 如何劫持https的请求,提供思路

  8. 前端如何进行seo优化; 前后端分离的项目如何seo

  9. 简单实现async/await中的async函数

  10. 1000-div问题:一次性插入1000个div。

    • 使用Fragment
    • 向1000个并排的div元素中,插入一个平级的div元素,如何优化插入的性能;先 display: none 然后插入 再 display: block ;赋予key,然后使用virtual-dom,先render,然后diff,最后patch;脱离文档流,用GPU去渲染,开启硬件加速;
  11. 2万小球问题:在浏览器端,用js存储2万个小球的信息,包含小球的大小,位置,颜色等,如何做到对这2万条小球信息进行最优检索和存储

    • 用ArrayBuffer实现极致存储
    • 哈夫曼编码 + 字典查询树实现更优索引
    • 用bit-map实现大数据筛查
    • 用hash索引实现简单快捷的检索
    • 用IndexedDB实现动态存储扩充浏览器端虚拟容量
    • 用iframe的漏洞实现浏览器端localStorage无限存储,实现2千万小球信息存储
  12. http的状态码中,499是什么?如何出现499,如何排查跟解决

    • 499对应的是 “client has closed connection”,客户端请求等待链接已经关闭,这很有可能是因为服务器端处理的时间过长,客户端等得“不耐烦”了。还有一种原因是两次提交post过快就会出现499。
      解决方法:1、前端将timeout最大等待时间设置大一些;2、nginx上配置proxy_ignore_client_abort on;
  13. 如何遍历一个dom树

  14. new操作符都做了什么

    • 创建一个空对象,并且 this 变量引用该对象,// lat target = {};
    • 继承了函数的原型。// target.proto = func.prototype;
    • 属性和方法被加入到 this 引用的对象中。并执行了该函数func// func.call(target);
    • 新创建的对象由 this 所引用,并且最后隐式的返回 this 。// 如果func.call(target)返回的res是个对象或者function 就返回它
  1. 请设计一个攻击服务器的策略;伪造虚假npm包 + nodejs版本的payload, nodejs的反序列化攻击
  2. 请写一个正则,去除掉html标签字符串里的所有属性,并保留src和href两种属性。答案
  3. 十万条数据插入数据库,怎么去优化和处理高并发情况下的DB插入。想法
  4. 一个iframe,内嵌了一个A页面,iframe的宽高不停变化,如何让A页面的宽高实时自适应这个iframe的宽高大小。请说出至少3种方法
  5. v8有了解过吗?讲讲了解过v8的那几个模块和部分
  6. 现在有多个spa的项目,有angular的,有vue的和react的,如何将他们合并成一个大统一的spa项目。提示

项目相关

  1. 怎么实现页面性能监控,首屏时间计算等
  2. 怎么实现一个JS错误监控

HTTP

  1. Http请求中的keep-alive有了解吗?
  2. http的状态码中,499是什么?如何出现499,如何排查跟解决
  3. http三次握手四次挥手,可以优化吗?
  4. 什么是断点续传?怎么实现?
  5. http 2.0 有什么特点,相比于 1.1 多了哪些优化?
  6. http中的对称加密和非对称加密
  7. 浏览器缓存机制
  8. 浏览器建立长连接
  9. http状态码206

代码实现

  1. 手写代码,简单实现call
  2. 手写代码,简单实现apply
  3. 手写代码,简单实现bind
  4. 简单手写实现promise、promise.all
  5. 实现一个Lazyman
  6. 用JS代码求出页面上一个元素的最终的background-color,不考虑IE浏览器,不考虑元素float情况。
  7. 实现一个 axios 的 timeout 方法
  8. 实现一个 render 方法进行模板字符串替换
  9. 实现一个new,说一说new执行了哪些操作
  10. 发布订阅模式
  11. 实现一个简单的Vue

HTML & CSS

  1. bootstrap是怎么实现grid系统
  2. BFC:清除浮动、margin重叠
  3. 两列等高布局的实现

源码相关

  1. Jquery的源代码怎么进行Object的深复制

Vue

  1. vue 中的一个 tick 是什么,node 中的 tick 呢
  2. vue 自定义指令
  3. vue 编译后是什么,runtime 的作用
  4. keep-alive

打包相关

  1. webpack常见使用
  2. fis、webpack等打包插件的原理
  3. webpack一些常用的使用功能:提取公共部分、代码分割和按需加载、treeShaking、webpack-dev-server等的一些使用
12…4

TiffanysBear

38 posts
16 categories
29 tags
© 2020 TiffanysBear | Site words total count: 55.4k
本站总访问量次 | 文章点击次数: | 本站浏览量: