-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
tingyuan
committed
May 15, 2024
1 parent
9181fe2
commit d5f7e54
Showing
7 changed files
with
194 additions
and
95 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,3 +35,5 @@ test.js | |
|
||
dev-dist | ||
hint-report | ||
|
||
a.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,61 @@ | ||
### 千分位分隔符 | ||
|
||
一串数字,使用千分位分隔符分隔开 | ||
如 100000 -> 100,000 | ||
|
||
10000000 -> 10,000,000 | ||
|
||
最简单的方式是使用正则表达式来实现,从末尾开始向前,每三个数字就插入一个分隔符 | ||
|
||
`/(\d{3})+$/` | ||
|
||
这样会匹配末尾之前三的整数倍的数字 | ||
|
||
> 关于正则量词可以参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers | ||
但实际我们要匹配的是三个数字之前的那个空白位置,分隔符需要被插入到该位置。这时需要用到前向断言`x(?=y)`,这个正则会匹配 x 但是要求 x 后面必须跟着 y,`(?=(\d{3}))`这样会匹配一个空白位置,后面跟着三个数字,这样正则变成了 `(?=(\d{3})+$)` | ||
|
||
> 关于正则断言可以参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions | ||
接下来需要处理开头的特殊情况,不处理的话如果数字恰好是三的整数倍,那么开头也会被插入分隔符 | ||
我们只需要不匹配开头即可,`/(?=(\B\d{3})+$)/g`,这里的元字符`\B`表示非单词边界,宽度为 0 | ||
|
||
> 关于正则元字符可以参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes | ||
```js | ||
var str = '10000000000', | ||
reg = /(?=(\B\d{3})+$)/g | ||
console.log(str.replace(reg, ',')) // 10,000,000,000 | ||
``` | ||
### 千分位分隔符 | ||
|
||
一串数字,使用千分位分隔符分隔开 | ||
如 100000 -> 100,000 | ||
|
||
10000000 -> 10,000,000 | ||
|
||
最简单的方式是使用正则表达式来实现,从末尾开始向前,每三个数字就插入一个分隔符 | ||
|
||
`/(\d{3})+$/` | ||
|
||
这样会匹配末尾之前三的整数倍的数字 | ||
|
||
> 关于正则量词可以参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers | ||
但实际我们要匹配的是三个数字之前的那个空白位置,分隔符需要被插入到该位置。这时需要用到前向断言`x(?=y)`,这个正则会匹配 x 但是要求 x 后面必须跟着 y,`(?=(\d{3}))`这样会匹配一个空白位置,后面跟着三个数字,这样正则变成了 `(?=(\d{3})+$)` | ||
|
||
> 关于正则断言可以参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions | ||
接下来需要处理开头的特殊情况,不处理的话如果数字恰好是三的整数倍,那么开头也会被插入分隔符 | ||
我们只需要不匹配开头即可,`/(?=(\B\d{3})+$)/g`,这里的元字符`\B`表示非单词边界,宽度为 0 | ||
|
||
> 关于正则元字符可以参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes | ||
```js | ||
var str = '10000000000', | ||
reg = /(?=(\B\d{3})+$)/g | ||
console.log(str.replace(reg, ',')) // 10,000,000,000 | ||
``` | ||
|
||
规则 描述 | ||
\ 转义 | ||
^ 匹配输入的开始 | ||
$ 匹配输入的结束 | ||
|
||
- 匹配前一个表达式 0 次或多次 | ||
|
||
* 匹配前面一个表达式 1 次或者多次。等价于 {1,} | ||
? 匹配前面一个表达式 0 次或者 1 次。等价于{0,1} | ||
. 默认匹配除换行符之外的任何单个字符 | ||
x(?=y) 匹配'x'仅仅当'x'后面跟着'y'。这种叫做先行断言 | ||
(?<=y)x 匹配'x'仅当'x'前面是'y'.这种叫做后行断言 | ||
x(?!y) 仅仅当'x'后面不跟着'y'时匹配'x',这被称为正向否定查找 | ||
(?<!y)x 仅仅当'x'前面不是'y'时匹配'x',这被称为反向否定查找 | ||
x|y 匹配‘x’或者‘y’ | ||
{n} n 是一个正整数,匹配了前面一个字符刚好出现了 n 次 | ||
{n,} n是一个正整数,匹配前一个字符至少出现了n次 | ||
{n,m} n 和 m 都是整数。匹配前面的字符至少n次,最多m次 | ||
[xyz] 一个字符集合。匹配方括号中的任意字符 | ||
[^xyz] 匹配任何没有包含在方括号中的字符 | ||
\b 匹配一个词的边界,例如在字母和空格之间 | ||
\B 匹配一个非单词边界 | ||
\d 匹配一个数字 | ||
\D 匹配一个非数字字符 | ||
\f 匹配一个换页符 | ||
\n 匹配一个换行符 | ||
\r 匹配一个回车符 | ||
\s 匹配一个空白字符,包括空格、制表符、换页符和换行符 | ||
\S 匹配一个非空白字符 | ||
\w 匹配一个单字字符(字母、数字或者下划线) | ||
\W 匹配一个非单字字符 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
## cookie | ||
|
||
### 格式 | ||
|
||
Set-Cookie: username=jimu; Domain=jimu.com; Path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Max-Age=347824; Secure; HttpOnly; SameSite=Lax; Partitioned | ||
|
||
Domain 和 Path 标识定义了 Cookie 的作用域:即 Cookie 应该发送给哪些 URL。 | ||
|
||
Domain 标识指定了哪些主机可以接受 Cookie。如果不指定,默认为当前主机,不包含子域名。如果指定了Domain,则一般包含子域名。例如,如果设置 `Domain=mozilla.org`,则 Cookie 也包含在子域名中(如`developer.mozilla.org`)。 | ||
Path则限制了cookie在有效域名下面可以生效的地址,例如Path=/docs,则以下地址都会匹配: | ||
|
||
- /docs | ||
- /docs/Web/ | ||
- /docs/Web/HTTP | ||
|
||
Expires表示cookie失效的时间,Max-Age表示cookie的生效时长(优先级更高),如果不设置Expires或者Max-Age那么这个cookie就是会话cookie,只在页面生命周期内有效 | ||
|
||
Secure表示限制访问协议必须是https,否则不生效 | ||
|
||
HttpOnly表示限制cookie无法通过JavaScript获取 | ||
|
||
SameSite表示限制第三方cookie的发送,它可以有效防止用户追踪以及降低CSRF的风险。它有三个值Strict, Lax, None。同站设置的cookie就是第一方cookie,跨站设置的cookie就属于第三方cookie(是否跨站会根据协议和域名公共后缀是否相同来判断)。现在SameSite的默认值是Lax,表示在点击链接,预加载请求,GET 表单这三类请求时会发送三方cookie,其余情况不会发送;Strict是任何情况都不会发送;None则是会发送(需要启用Secure属性才有效)。 | ||
|
||
[Partitioned](https://developer.mozilla.org/zh-CN/docs/Web/Privacy/Privacy_sandbox/Partitioned_cookies)表示分区cookie | ||
|
||
### 限制 | ||
|
||
1. 设置cookie时,Domain只能指定为当前域名或者其父域名,否则cookie会被拒绝设置 | ||
2. 指定了Domain的cookie在其及其子域名下面都有效,例如 foo=a; Domain=example.com; foo在example.com及其子域名下都是生效的 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,74 @@ | ||
[meta]: nodejs "title: 'Koa和express的中间件', keywords: 'middleware', date: '2020-8-22'" | ||
|
||
## Koa 和 Express 的中间件机制 | ||
|
||
### Koa | ||
|
||
```javascript | ||
const createServer = (req, res) => { | ||
const ctx = createContext(req, res) | ||
ctx.res.statusCode = 404 | ||
const fnMiddleware = compose(middlewares) | ||
return fnMiddleware(ctx) | ||
.then(() => finalRespond(ctx)) | ||
.catch((err) => ctx.onerror(err)) | ||
} | ||
// 洋葱模型 | ||
function compose(middlewares) { | ||
return function (context, next) { | ||
let index = -1 // last called middleware # | ||
return dispatch(0) | ||
function dispatch(i) { | ||
if (i <= index) return Promise.reject(new Error('next() called multiple times')) | ||
index = i | ||
let fn = middlewares[i] | ||
// 当i等于中间件队列长度时表示最后一个中间件正在调用next | ||
if (i === middlewares.length) fn = next | ||
// 这里next是空的就直接resolve返回即可,之后就是从洋葱芯回到表皮的过程 | ||
if (!fn) return Promise.resolve() | ||
try { | ||
// 这里可以看到,调用next方法其实就是调用下一个中间件 | ||
return Promise.resolve(fn(context, dispatch.bind(null, i + 1))) | ||
} catch (err) { | ||
return Promise.reject(err) | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
### Express | ||
|
||
Express 中间件其实和 Koa 类似,也是从上到下的执行流程,当调用`next`的时候,express 会执行下一个中间件,如果没调用`next`并且也没有返回响应,那么 express 会挂起,前端就一直等待,而 Koa 则不同,不调用`next`只是不会调用剩余的中间件,但最终还是会返回响应;另外 express 的中间件是同步调用的,意味着如果中间件有异步操作,`next`也不会等待异步完成,而就只是线性的调用下一个中间件 | ||
|
||
```javascript | ||
// 伪代码 | ||
function dispatch(req, res, done) { | ||
var idx = 0 | ||
var stack = this.stack | ||
if (stack.length === 0) return done() | ||
next() | ||
function next(err) { | ||
var layer = stack[idx++] // 因为express注册中间件途径多种多样,每个中间件都会被抽象成layer | ||
if (err === 'route' || err === 'router' || !layer) return done(err) | ||
if (err) { | ||
layer.handle_error(err, req, res, next) | ||
} else { | ||
layer.handle_request(req, res, next) | ||
} | ||
} | ||
} | ||
``` | ||
|
||
--- | ||
|
||
总结来讲,Koa 和 Express 的中间件区别主要在于,express 是依靠主动调用`res.end`来响应请求,koa 则只是向 ctx 挂载数据,中间件执行完再返回响应;二者都是通过`next`来调用下一个中间件,区别在于 express 不会等待异步的中间件执行完,而 koa 会强制让你`await next()`才可以 | ||
[meta]: nodejs "title: 'Koa和express的中间件', keywords: 'middleware', date: '2020-8-22'" | ||
|
||
## Koa 和 Express 的中间件机制 | ||
|
||
### Koa | ||
|
||
```js | ||
app.use(async (ctx, next) => { | ||
const start = Date.now() | ||
await next() | ||
const ms = Date.now() - start | ||
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`) | ||
}) | ||
``` | ||
|
||
```javascript | ||
const createServer = (req, res) => { | ||
const ctx = createContext(req, res) | ||
ctx.res.statusCode = 404 | ||
const fnMiddleware = compose(middlewares) | ||
return fnMiddleware(ctx) | ||
.then(() => finalRespond(ctx)) | ||
.catch((err) => ctx.onerror(err)) | ||
} | ||
// 洋葱模型 | ||
function compose(middlewares) { | ||
return function (context, next) { | ||
let index = -1 // last called middleware # | ||
return dispatch(0) | ||
function dispatch(i) { | ||
if (i <= index) return Promise.reject(new Error('next() called multiple times')) | ||
index = i | ||
let fn = middlewares[i] | ||
// 当i等于中间件队列长度时表示最后一个中间件正在调用next | ||
if (i === middlewares.length) fn = next | ||
// 这里next是空的就直接resolve返回即可,之后就是从洋葱芯回到表皮的过程 | ||
if (!fn) return Promise.resolve() | ||
try { | ||
// 这里可以看到,调用next方法其实就是调用下一个中间件 | ||
return Promise.resolve(fn(context, dispatch.bind(null, i + 1))) | ||
} catch (err) { | ||
return Promise.reject(err) | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
### Express | ||
|
||
Express 中间件其实和 Koa 类似,也是从上到下的执行流程,当调用`next`的时候,express 会执行下一个中间件,如果没调用`next`并且也没有返回响应,那么 express 会挂起,前端就一直等待,而 Koa 则不同,不调用`next`只是不会调用剩余的中间件,但最终还是会返回响应;另外 express 的中间件是同步调用的,意味着如果中间件有异步操作,`next`也不会等待异步完成,而就只是线性的调用下一个中间件 | ||
|
||
```javascript | ||
// 伪代码 | ||
function dispatch(req, res, done) { | ||
var idx = 0 | ||
var stack = this.stack | ||
if (stack.length === 0) return done() | ||
next() | ||
function next(err) { | ||
var layer = stack[idx++] // 因为express注册中间件途径多种多样,每个中间件都会被抽象成layer | ||
if (err === 'route' || err === 'router' || !layer) return done(err) | ||
if (err) { | ||
layer.handle_error(err, req, res, next) | ||
} else { | ||
layer.handle_request(req, res, next) | ||
} | ||
} | ||
} | ||
``` | ||
|
||
--- | ||
|
||
总结来讲,Koa 和 Express 的中间件区别主要在于,express 是依靠主动调用`res.end`来响应请求,koa 则只是向 ctx 挂载数据,中间件执行完再返回响应;二者都是通过`next`来调用下一个中间件,区别在于 express 不会等待异步的中间件执行完,而 koa 会强制让你`await next()`才可以 |