- nodejs 官网
- NodeJS 从入门到精通 http https http2 的区别与实践
单线程
非阻塞IO
事件驱动
每个线程需要耗费大约2MB内存。也就是说,理论上,一个8GB内存的服务器可以同时连接的最大用户数为4000个左右。
需要复习一下模块
- require() 源码解读(nodejs 加载机制)
- CommonJS 模块的重要特性是加载时执行,即脚本代码在 require 的时候,就会全部执行。一旦出现某个模块被”循环加载”,就只输出已经执行的部分,还未执行的部分不会输出。
- ES6 模块是动态引用,如果使用 import 从一个模块加载变量,那些变量不会被缓存,而是成为一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值。
- import/export 最终都是编译为 require/exports 来执行的。
- CommonJS 规范规定,每个模块内部,module 变量代表当前模块。这个变量是一个对象,它的 exports 属性(即 module.exports )是对外的接口。加载某个模块,其实是加载该模块的 module.exports 属性。
- export 命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。
- CommonJS运行时加载
CommonJS 模块输出的是一个值的拷贝,
- ES6编译时加载(或叫静态加载)
ES6 模块是动态引用 ES6 模块输出的是值的引用。
export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。
import命令具有提升效果,会提升到整个模块的头部,首先执行。
如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。
export 如果后面跟的是会变量提升的 var/function,那么会变量提升 module.exports/exports 不会变量提升
nodejs 暴露模块需要用 module.exports,其实 exports = module.exports,当我们给 epxorts.a = xxx 时,其实就是在 module.exports 上加属性
这就是为什么不能给 exports 赋值的原因,即赋值会改变 exports 的指向
event
http/http2/https url buffer fs path querystring
console debugger global process child_process readline cluster
npm init egg --type=simple
// 等价于
npx create-egg --type=simple
egg egg-init egg-bin egg-scripts
callback promise generator async
"z" === "z"; // true
"\172" === "z"; // true 8进制
"\x7A" === "z"; // true 16进制
"\u007A" === "z"; // true utf-16编码
"\u{7A}" === "z"; // true utf-16编码
简单讲就是 utf-16 编码转换
由于 JavaScript 采用 IEEE 754 标准,数值存储为 64 位双精度格式,数值精度最多可以达到 53 个二进制位(1 个隐藏位与 52 个有效位)。 范围: -Math.pow(2,53) ~ Math.pow(2,53) 不包括两个端点
32 为的浮点数 分为 3 部分:
第一部分是符号位,用 s 表示,代表正负,要记住的是在浮点数的范围内,所有数字都是有符号的;
第二部分是指数位,用 e 表示,代表指数,用 8 位 bit 表示的数字范围是 0255,为了同时表示大数和小数,我们把 0255 去掉头尾(0,255 后面会用到)的 1254 去映射到-126127,这样同时可以表示最大最小数字;
第三部分是有效数位,用 f 表示,代表的是有效的数位;
综合上述表示和科学计数法,我们的浮点数就可以表示为公式
(-1)^s * 1.f * 2^e
(1)函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误。
(3)不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。
ES5 对空位的处理,已经很不一致了,大多数情况下会忽略空位。
forEach(), filter(), reduce(), every() 和 some()都会跳过空位。 map()会跳过空位,但会保留这个值 join()和 toString()会将空位视为 undefined,而 undefined 和 null 会被处理成空字符串。
ES6 则是明确将空位转为 undefined。
[, "a", undefined, null].join("#"); // "#a##"
[, "a", undefined, null].toString(); // ",a,,"
Object.create 第二个参数是对象描述
const obj = Object.create({}, { p: { value: 42 } }); // p是不可枚举的
Object.values(obj); // []
const obj = Object.create(
{},
{
p: {
value: 42,
enumerable: true,
},
}
);
Object.values(obj); // [42]
- javaScript 遍历对象、数组总结 对象的属性分为三种: 是否是自身属性 是否可以枚举 是否是 Symbol 属性 注意:对象没有 for...of...
对象的扩展运算符(...)用于取出参数对象自身
的所有可遍历
属性,拷贝到当前对象之中。
举个栗子
var a = { a: 1 };
Object.defineProperty(a, "aa", {
value: 3,
});
var b = { b: 2 };
b.__proto__ = a;
Object.defineProperty(b, "c", {
value: 3,
});
b[Symbol()] = 4;
Object.keys(b); // ["b"] 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性).
for (var i in b) {
console.log(i, ":", b[i]);
} // b : 2 a : 1 循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)
Object.getOwnPropertyNames(obj); // ["b", "c"] 返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性).
Reflect.ownKeys(b); // ["b", "c", Symbol()] 返回一个数组,包含对象自身的所有属性,不管属性名是Symbol或字符串,也不管是否可枚举.
var c = { ...b }; // {b: 2, Symbol(): 4}
async继发与并发
// 继发
let foo = await getFoo();
let bar = await getBar();
// 并发
// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
// 继发
// 方法一
async function dbFuc(db) { //这里不需要 async
let docs = [{}, {}, {}];
for (let doc of docs) {
await db.post(doc);
}
}
// 方法二
async function dbFuc(db) {
let docs = [{}, {}, {}];
await docs.reduce(async (_, doc) => {
await _;
await db.post(doc);
}, undefined);
}
// 并发
function dbFuc(db) { //这里不需要 async
let docs = [{}, {}, {}];
// 可能得到错误结果
docs.forEach(async function (doc) {
await db.post(doc);
});
}
async function dbFuc(db) {
let docs = [{}, {}, {}];
let promises = docs.map((doc) => db.post(doc));
let results = await Promise.all(promises);
console.log(results);
}
// 或者使用下面的写法
async function dbFuc(db) {
let docs = [{}, {}, {}];
let promises = docs.map((doc) => db.post(doc));
let results = [];
for (let promise of promises) {
results.push(await promise);
}
console.log(results);
}
super
指向当前对象的原型对象
注意,super 关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。 目前,只有对象方法的简写法可以让 JavaScript 引擎确认,定义的是对象的方法。
// 报错
const obj = {
foo: super.foo,
};
// 报错
const obj = {
find: () => super.foo,
};
// 报错
const obj = {
find: function() {
return super.foo;
},
};
// 正确
const obj = {
foo: "world",
find() {
return super.foo;
},
};
const o = Object.create({ x: 1, y: 2 });
o.z = 3;
let { x, ...newObj } = o;
let { y, z } = newObj;
x; // 1
y; // undefined
z; // 3
const obj = {
f() {
this.foo = "bar";
},
};
new obj.f(); // 报错
如果对象的方法使用了取值函数(getter)和存值函数(setter),则 name 属性不是在该方法上面,而是该方法的属性的描述对象的 get 和 set 属性上面,返回值是方法名前加上 get 和 set。
const obj = {
get foo() {},
set foo(x) {},
};
obj.foo.name;
// TypeError: Cannot read property 'name' of undefined
const descriptor = Object.getOwnPropertyDescriptor(obj, "foo");
descriptor.get.name; // "get foo"
descriptor.set.name; // "set foo"
new Function().name; // "anonymous"
var doSomething = function() {
// ...
};
doSomething.name; // "doSomething"
doSomething.bind().name; // "bound doSomething"
const key1 = Symbol("description");
const key2 = Symbol();
let obj = {
[key1]() {},
[key2]() {},
};
obj[key1].name; // "[description]"
obj[key2].name; // ""
-
可以用来处理数组,但是会把数组视为对象 Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3]
-
取值函数的处理
const source = {
get foo() {
return 1;
},
};
const target = {};
Object.assign(target, source);
// { foo: 1 }
export *
命令会忽略模块的 default 方法
export var a = 1;
// 或者
var a = 1;
export { a };
export defalut 1
// modules.js
function add(x, y) {
return x * y;
}
export { add as default };
// 等同于
// export default add;
// app.js
import { default as foo } from "modules";
// 等同于
// import foo from 'modules';
- super的指向以及super中this的指向问题
super可以作为函数和对象使用
作为函数时指向父类的构造函数,只能在构造函数中使用
作为对象时,在普通方法中指向父类原型对象,在静态方法中指向父类
super调用的方法中this指向,普通方法中this指向自身实例,静态方法中指向自身类
super在普通方法中等于this
易错题
class A {
constructor() {
this.x = 1;
}
}
class B extends A {
constructor() {
super();
this.x = 2;
super.x = 3; // super等于this
console.log(super.x); // undefined
console.log(this.x); // 3
}
}
let b = new B();
注意 babel 只转换新的句法(语法),不会转换新的 API,比如 Iterator、Generator、Set、Map、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转码。
- caniuse
- browserlist(查看浏览器市场占比)
- kangax(查看 es6 支持情况)
- 都 2020 了,还不懂 js 运算符优先级?
- 「前端进阶」从多线程到 Event Loop 全面梳理(宏任务微任务 cup 进程线程)
https://developer.mozilla.org/zh-CN/docs/Web/API/PerformanceTiming
先看 configurable,再看 writable configurable 为 false 表示不能修改属性描述符,不能删除属性 configurable 和 writable 同时为 fasle 时,不可以修改任何描述符 configurable 为 false 时,只可以修改 writable
扩展:
严格模式下 o.a 会报错
Object.isExtensible() Object.seal() // 方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。 Object.isSealed() Object.freeze() // 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。 Object.isFrozen() Object.preventExtensions() // 方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。
vue vue-router vuex vue-ssr nuxt 实现自己的 vue2 vue3
// TODO:vue-cli
- 描述下diff算法
实现一个 react
-
域名预解析
-
域名分散处理, 突破浏览器对单个域名的最大并发连接数 分散到 img0.guoweiwei.com/img1.guoweiwei.com/img2.guoweiwei.com/…等不同域名
- 一文读懂前端缓存
- 浏览器缓存策略(注意有个启发式缓存的过程)
- web性能优化之:no-cache与must-revalidate深入探究
prefetch(预取):将来某些导航下可能需要的资源 preload(预加载):当前导航下可能需要资源
与 prefetch 指令相比,preload 指令有许多不同之处:
preload chunk 会在父 chunk 加载时,以并行方式开始加载。prefetch chunk 会在父 chunk 加载结束后开始加载。 preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。 preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。 浏览器支持程度不同。
什么是BFC?BFC的好处是什么? 如何创建BFC?
display: none 和visibility: hidden 和opacity: 0的区别
display: none; DOM 结构:浏览器不会渲染 display 属性为 none 的元素,不占据空间; 事件监听:无法进行 DOM 事件监听; 性能:动态改变此属性时会引起重排,性能较差; 继承:不会被子元素继承,毕竟子类也不会被渲染; transition:transition 不支持 display。
visibility: hidden; DOM 结构:元素被隐藏,但是会被渲染不会消失,占据空间; 事件监听:无法进行 DOM 事件监听; 性 能:动态改变此属性时会引起重绘,性能较高; 继 承:会被子元素继承,子元素可以通过设置 visibility: visible; 来取消隐藏; transition:transition 不支持 visibility
opacity: 0; DOM 结构:透明度为 100%,元素隐藏,占据空间; 事件监听:可以进行 DOM 事件监听; 性 能:提升为合成层,不会触发重绘,性能较高; 继 承:会被子元素继承,且,子元素并不能通过 opacity: 1 来取消隐藏; transition:transition 支持 opacity。
https://www.runoob.com/cssref/css-selectors.html
- 面试被问感情状况,怎样回答最加分? 先找到一份满意的工作,让自己经济独立才是最为重要。
站内优化
- 内容优化,我们的网站是博客?落地页?论坛社区?
- 关键词优化
- 标题
- Meta信息号称TKD元描述,就是Title/Description/Keyword 如何查看一个网站的Meta信息?最方便的就是安装Chrome的一个插件:meta seo inspector
- 导航一般是面包屑导航
- 内链优化的有助于我们给站内不同的页面导流,传递页面权重
- 图片最好加ALT标签
- 标签嵌套层次不能太深
技术性优化
- 加载速度
- 移动适配 Google搜索的63%来自移动设备
- 重复内容检测 网站的重复内容过多,会让Google认为该站的质量很低,从而降低网站的评分
- 不要让网站出现大量404页面
- 重定向,不要删除之前的
- sitemap.xml
- robots.txt
站外优化
- 友情链接
- 社区推广
- 社交网站
- 掏钱买
怎么优化 通过谷歌分析,看跳出率来定位问题
首先我们会有一个前端监控系统,通过这个系统我们可以看到用户的行为轨迹,可以还原一个用户现场, 其次我们会看看测试同学有没有线索,能不能还原现场, 无法还原现场的,我们会通过调试代码的方式,进行一个排查
常见的错误: 用户的数据缓存问题 脚本的版本问题 用户的数据比较特殊,比如确实某个字段, 没有进行一个容错,
通用
- 提升webpack的版本
- 并行打包
- loader里面设置include\exclude
- 每个额外的 loader/plugin 都有启动时间。尽量少使用不同的工具。
- 尽量少用resolve
- 使用 cache-loader 启用持久化缓存
开发环境
- 在内存中编译,用webpack-dev-server
- 增量编译,开启hot
- Devtool 设置source-map
- 避免在生产环境下才会用到的工具, 如压缩代码
生产环境
- 多个编译时 parallel-webpack
- Source maps
- 首屏优化
- 内存优化
- 应用骨架屏
- 对代码进行分包
- 如果是多图片的话 进行图片懒加载
- 如果有很多小图标的话 就利用雪碧图
- 懒加载 可以按路由进行加载
- dns prefetch
- async defer
- preload prefetch
- ssr
- 管理就是通过下属实现经营者的目标,管理只不能简单复述领导层的话,需要加上自己的理解,并变成可以执行的任务,分配给下属
- 主要分为业务管理、员工管理
- 管理团队要有一个好的、透明的晋升机制,做的好的就需要奖励,做的不好也要严厉批评
- 要根据下属的性格(ffs测试)、意愿、能力等综合分析,把对的人安排到对的位置上,这样才能实现1+1>2的效果
- 要适度的区分指示和人文关怀
- 面试候选人或者提拔下属,需要选择跟公司价值观一致的候选人
- 遇到问题,需要保护好自己的下属,自己来担责,这样下属才会有冲劲
- 使用目标管理,让团队成员理解目标,并需告知目标是一定要完成的
- 作为管理者,一定要比下属看得远,需要指引下属往对的方向发展
- 业务管理,分配任务,并告知详细执行,然后中间主动询问进度等,也可让下属自己汇报
- 让下属自己汇报自己的成绩,保证公平公正
- eslint 代码规范
- code review(这里介绍公司的四个环境)
顶部有平台的一般都有性能问题