const s = ‘foo foo foo’
s.replce(/foo/g, ‘bar’)
那如题中,「是否可以使用正则表达式来替代子串」
答:「不可以,因为使用子串构建正则时,有可能有特殊字符,就有可能出现问题」,如下
// 期待结果: 'AhelloX hello3 ’
'hello. helloX hello3 '.replace(new RegExp('hello. ', ‘g’), ‘A’)
< “AAA”
而在 javascript
中替换子串只能使用一种巧妙的办法:str.split('foo').join('bar')
'hello. hello. hello. '.split('hello. ').join(‘A’)
< “AAA”
真是一个巧(笨)妙(拙)的办法啊!!!!!「大概 TC39 也意识到了一个问题,于是出了一个新的 API」,在 ESNext
中
String.prototype.replaceAll()
‘aabbcc’.replaceAll(‘b’, ‘.’);
// ‘aa…cc’
详细文档在 String.prototype.replaceAll[10]
总结(及直接答案)
两种办法
-
str.split('foo').join('bar')
-
str.replaceAll('foo', 'bar')
,在ESNext
中,目前支持性不好
05 如何获取一个进程的内存并监控
❝ 更多描述: 在编写脚本时,有时会出现内存过大发生 OOM 的事情,那我们如何得知某个进程的内存?另外又如何监控它 ❞
❝
在 Issue 中交流与讨论: 05 如何获取一个进程的内存并监控[11]
❞
通过 ps
可以获知一个进程所占用的内存
$ ps -O rss -p 3506
PID RSS S TTY TIME COMMAND
3506 6984 S pts/1 00:00:00 vim
如果要监控内存,肯定使用对进程万能的命令 pidstat
(PS: 这名字一听就知道是干嘛的)
## -r 显示内存信息
## -p 指定 pid
## 1: 每个一秒打印一次
$ pidstat -r -p 3506 1
Linux 3.10.0-957.21.3.el7.x86_64 (shanyue) 11/04/19 x86_64 (2 CPU)
20:47:35 UID PID minflt/s majflt/s VSZ RSS %MEM Command
20:47:36 0 3506 0.00 0.00 139940 6984 0.18 vim
20:47:37 0 3506 0.00 0.00 139940 6984 0.18 vim
20:47:38 0 3506 0.00 0.00 139940 6984 0.18 vim
20:47:39 0 3506 0.00 0.00 139940 6984 0.18 vim
20:47:40 0 3506 0.00 0.00 139940 6984 0.18 vim
20:47:41 0 3506 0.00 0.00 139940 6984 0.18 vim
pidstat
是属于 sysstat
下的 linux 性能工具,但在 mac 中,如何定位内存的变化?此时可以使用万能的 top/htop
$ htop -p 31796
总结
简而言之,有以下三个命令
-
pidstat -r
-
htop/top -p
-
ps -O rss -p
关于更多指标的监控可以参考我的文章: linux 各项监控指标小记[12]
06 CORS 如果需要指定多个域名怎么办
❝
在 Issue 中交流与讨论: 06 CORS 如果需要指定多个域名怎么办[13]
❞
CORS
通过控制 Access-Control-Allow-Origin
控制哪些域名可以共享资源,取值如下
Access-Control-Allow-Origin: | *
其中 *
代表所有域名,origin
代表指定特定域名,那如何设置多个域名了?
此时需要通过代码实现,「根据请求头中的 Origin
来设置响应头 Access-Control-Allow-Origin
」,那 Origin 又是什么东西?
请求头: Origin
并不是所有请求都会自动带上 Origin
,在浏览器中带 Origin
的逻辑如下
-
如果存在跨域,则带上
Origin
,值为当前域名 -
如果不存在跨域,则不带
Origin
逻辑理清楚后,关于服务器中对于 Access-Control-Allow-Origin
设置多域名的逻辑也很清晰了
-
如果请求头不带有
Origin
,证明未跨域,则不作任何处理 -
如果请求头带有
Origin
,证明跨域,根据Origin
设置相应的Access-Control-Allow-Origin: <Origin>
使用伪代码实现如下:
// 获取 Origin 请求头
const requestOrigin = ctx.get(‘Origin’);
// 如果没有,则跳过
if (!requestOrigin) {
return await next();
}
// 设置响应头
ctx.set(‘Access-Control-Allow-Origin’, requestOrigin)
Vary: Origin
此时可以给多个域名控制 CORS,但此时假设有两个域名访问 static.shanyue.tech
的跨域资源
-
foo.shanyue.tech
,响应头中返回Access-Control-Allow-Origin: foo.shanyue.tech
-
bar.shanyue.tech
,响应头中返回Access-Control-Allow-Origin: bar.shanyue.tech
看起来一切正常,但如果中间有缓存怎么办?
-
foo.shanyue.tech
,响应头中返回Access-Control-Allow-Origin: foo.shanyue.tech
,被 CDN 缓存 -
「
bar.shanyue.tech
,因由缓存,响应头中返回Access-Control-Allow-Origin: foo.shanyue.tech
,跨域出现问题」
此时,Vary: Origin
就上场了,代表为不同的 Origin
缓存不同的资源
总结 (简要答案)
CORS 如何指定多个域名?
「根据请求头中的 Origin
来设置响应头 Access-Control-Allow-Origin
」,思路如下
-
总是设置
Vary: Origin
,避免 CDN 缓存破坏 CORS 配置 -
如果请求头不带有
Origin
,证明未跨域,则不作任何处理 -
如果请求头带有
Origin
,证明浏览器访问跨域,根据Origin
设置相应的Access-Control-Allow-Origin: <Origin>
使用伪代码实现如下
// 获取 Origin 请求头
const requestOrigin = ctx.get(‘Origin’);
ctx.set(‘Vary’, ‘Origin’)
// 如果没有,则跳过
if (!requestOrigin) {
return await next();
}
// 设置响应头
ctx.set(‘Access-Control-Allow-Origin’, requestOrigin)
❝
相关问题:如何避免 CDN 为 PC 端缓存移动端页面[14]
❞
07 既然 cors 配置可以做跨域控制,那可以防止 CSRF 攻击吗
❝
在 Issue 中交流与讨论: 07 既然 cors 配置可以做跨域控制,那可以防止 CSRF 攻击吗 [15]
❞
「对 CORS 一点用也没有」
-
「
form
提交不通过CORS
检测」,你可以在本地进行测试 -
即使通过
xhr
及fetch
进行提交被 CORS 拦住,「但是对于简单请求而言,请求仍被发送」,已造成了攻击
08 如何避免 CDN 为 PC 端缓存移动端页面
❝
在 Issue 中交流与讨论: 08 如何避免 CDN 为 PC 端缓存移动端页面[16]
❞
如果 PC 端和移动端是一套代码则不会出现这个问题。「这个问题出现在 PC 端和移动端是两套代码,却共用一个域名。」
使用 nginx
配置如下,根据 UA 判断是否移动端,而走不同的逻辑 (判断 UA 是否移动端容易出问题)
location / {
// 默认 PC 端
root /usr/local/website/web;
判断 UA,访问移动端
if ( $http_user_agent ~* “(Android|webOS|iPhone|iPad|BlackBerry)” ){
root /usr/local/website/mobile;
}
index index.html index.htm;
}
解决方案通常使用 Vary
响应头,来控制 CDN 对不同请求头的缓存。
「此处可以使用 Vary: User-Agent
,代表如果 User-Agent 不一样,则重新发起请求,而非从缓存中读取页面」
Vary: User-Agent
当然,User-Agent
实在过多,此时缓存失效就会过多。
简答
使用 Vary: User-Agent
,根据 UA 进行缓存。
Vary: User-Agent
但最好不要出现这种情况,PC 端和移动端如果是两套代码,建议用两个域名,理由如下
-
nginx
判断是否移动端容易出错 -
对缓存不友好
09 如何实现表格单双行条纹样式
❝
在 Issue 中交流与讨论: 09 如何实现表格单双行条纹样式[17]
❞
通过 css3
中伪类 :nth-child
来实现。其中 :nth-child(an+b)
匹配下标 { an + b; n = 0, 1, 2, ...}
且结果为整数的子元素
-
nth-child(2n)
/nth-child(even)
: 双行样式 -
nth-child(2n+1)
/nth-child(odd)
: 单行样式
其中 tr
在表格中代表行,实现表格中单双行样式就很简单了:
tr:nth-child(2n) {
background-color: red;
}
tr:nth-child(2n+1) {
background-color: blue;
}
同理:
-
如何匹配最前三个子元素:
:nth-child(-n+3)
-
如何匹配最后三个子元素:
:nth-last-child(-n+3)
10 简述下 css specificity
❝
在 Issue 中交流与讨论: 10 简述下 css specificity[18]
❞
css specificity
即 css 中关于选择器的权重,以下三种类型的选择器依次下降
-
id
选择器,如#app
-
class
、attribute
与pseudo-classes
选择器,如.header
、[type="radio"]
与:hover
-
type
标签选择器和伪元素选择器,如h1
、p
和::before
其中通配符选择器 *
,组合选择器 + ~ >
,否定伪类选择器 :not()
对优先级无影响
另有内联样式 <div class="foo" style="color: red;"></div>
及 !important
(最高) 具有更高的权重
❝
`:not` 的优先级影响 - codepen[19] 可以看出
:not
对选择器的优先级无任何影响
❞
11 node 中 module.exports 与 exports 有什么区别
❝
在 Issue 中交流与讨论: 11 node 中 module.exports 与 exports 有什么区别[20]
❞
「一句话:exports
是 module.exports
的引用,如果 exports
没有重赋值,则二者没有任何区别」
类似如下所示
const exports = module.exports
那如下结果会如何导出?
module.exports = 100
exports = 3
很显然会导出 100,毕竟 exports
进行了重赋值。
「那在 node 源码中如何实现的呢?」 从源码里可以看出 「exports」 的实质
module wrapper
详见源码: https://github.com/nodejs/node/blob/master/lib/internal/modules/cjs/loader.js#L1252,可以看出符合猜想
众所周知,node 中所有的模块代码都被包裹在这个函数中
(function(exports, require, module, __filename, __dirname) {
exports.a = 3
});
而以下源码指出,exports
是如何得来
const dirname = path.dirname(filename);
const require = makeRequireFunction(this, redirects);
let result;
// 从这里可以看出来 exports 的实质
const exports = this.exports;
const thisValue = exports;
const module = this;
if (requireDepth === 0) statCache = new Map();
if (inspectorWrapper) {
result = inspectorWrapper(compiledWrapper, thisValue, exports,
require, module, filename, dirname);
} else {
// 这里是模块包装函数
result = compiledWrapper.call(thisValue, exports, require, module,
filename, dirname);
}
12 如何获取当前系统中的在线用户数 (并发用户数)
❝ 更多描述: 一些 SaaS 系统基于 Pricing 的考虑,会限制团队人数及同时在线数,如何实现 ❞
❝
在 Issue 中交流与讨论: 12 如何获取当前系统中的在线用户数 (并发用户数)[21]
❞
❝
一些 SaaS 系统基于定价策略的考虑,会限制团队人数及同时在线数,如何实现?
❞
通过 redis
的 zset
可实现并发用户数。
当一个用户请求任何接口时,实现一个 middleware,处理以下逻辑
// 当一个用户访问任何接口时,对该用户Id,写入 zset
await redis.zadd(Organization:${organizationId}:concurrent
, Date.now(), User:${userId}
)
// 查询当前机构的并发数
// 通过查询一分钟内的活跃用户来确认并发数,如果超过则抛出特定异常
const activeUsers = await redis.zrangebyscore(Organization:${organizationId}:concurrent
, Date.now() - 1000 * 60, Date.now())
// 查出并发数
const count = activeUsers.length
// 删掉过期的用户
await redis.zrembyscore(Organization:${organizationId}:concurrent
, Date.now() - 1000 * 60, Date.now())
总结
-
每当用户访问服务时,把该用户的 ID 写入优先级队列,权重为当前时间
-
根据权重(即时间)计算一分钟内该机构的用户数
-
删掉一分钟以上过期的用户
13 如何把 json 数据转化为 demo.json 并下载文件
❝
在 Issue 中交流与讨论: 13 如何把 json 数据转化为 demo.json 并下载文件[22]
❞
json 视为字符串,可以利用 DataURL
进行下载
Text -> DataURL
除了使用 DataURL,还可以转化为 Object URL 进行下载
Text -> Blob -> Object URL
可以把以下代码直接粘贴到控制台下载文件
function download (url, name) {
const a = document.createElement(‘a’)
a.download = name
a.rel = ‘noopener’
a.href = url
// 触发模拟点击
a.dispatchEvent(new MouseEvent(‘click’))
// 或者 a.click()
}
const json = {
a: 3,
b: 4,
c: 5
}
const str = JSON.stringify(json, null, 2)
// 方案一:Text -> DataURL
const dataUrl = data:,${str}
download(dataUrl, ‘demo.json’)
// 方案二:Text -> Blob -> ObjectURL
const url = URL.createObjectURL(new Blob(str.split(‘’)))
download(url, ‘demo1.json’)
总结
-
模拟下载,可以通过新建一个
<a href="url" download><a>
标签并设置url
及download
属性来下载 -
可以通过把
json
转化为dataurl
来构造 URL
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
react和vue的比较
相同
1)vitual dom
2)组件化
3)props,单一数据流
不同点
1)react是jsx和模板;(jsx可以进行更多的js逻辑和操作)
2)状态管理(react)
3)对象属性(vue)
4)vue:view——medol之间双向绑定
5)vue:组件之间的通信(props,callback,emit)
son 转化为
dataurl` 来构造 URL
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-8ONHfdQt-1712008166754)]
[外链图片转存中…(img-f3fOeyPr-1712008166755)]
[外链图片转存中…(img-WZh3QjpY-1712008166755)]
[外链图片转存中…(img-cfnpwJKy-1712008166755)]
[外链图片转存中…(img-qkeh2QUj-1712008166756)]
[外链图片转存中…(img-8wMpkh8i-1712008166756)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-uRM9OBtV-1712008166756)]
react和vue的比较
相同
1)vitual dom
2)组件化
3)props,单一数据流
不同点
1)react是jsx和模板;(jsx可以进行更多的js逻辑和操作)
2)状态管理(react)
3)对象属性(vue)
4)vue:view——medol之间双向绑定
5)vue:组件之间的通信(props,callback,emit)
[外链图片转存中…(img-BSPwgjUK-1712008166757)]