Open into-piece opened 4 years ago
var paramsString = "q=URLUtils.searchParams&topic=api" var searchParams = new URLSearchParams(paramsString); for (let p of searchParams) { console.log(p); } searchParams.has("topic") === true; // true searchParams.get("topic") === "api"; // true searchParams.getAll("topic"); // ["api"] searchParams.get("foo") === null; // true searchParams.append("topic", "webdev"); searchParams.toString(); // "q=URLUtils.searchParams&topic=api&topic=webdev" searchParams.set("topic", "More webdev"); searchParams.toString(); // "q=URLUtils.searchParams&topic=More+webdev" searchParams.delete("topic"); searchParams.toString(); // "q=URLUtils.searchParams"
手动实现
class URLSearchParams { constructor(obj) { this.params = new Map(); if (Object.prototype.toString.call(obj) === "[object String]") { obj.split("&").forEach((item) => { const [key, value] = item.split("="); this.params.set(key, value); console.log(this.params); }); } if (obj instanceof Object) { Object.keys(obj).forEach((item) => { this.params.set(item, obj[item]); }); } } get(k) { return this.params.get(k); } set(k, v) { return this.params.set(k, v); } has(k) { return this.params.has(k); } append() {} toString() { // for (let [key, value] of this.params.entries()) { // } // [...map.entries()] // this.params.forEach(function(value, key, map) { // str+= `${key}=${value]}` // }); const arr = [...this.params]; const str = arr.reduce((res, [key, value], index) => { res += `${key}=${value}${index === arr.length - 1 ? "" : "&"}`; return res; }, ""); return str; } // 可遍历 *[Symbol.iterator]() { yield* this.params; } }
nodejs有一个叫vm的模块,这是用来运行代码的模块。怎么说呢,我们知道浏览器只要你将代码放在script标签中,或script src远程引用它,代码就会执行,这些代码会执行一些我们没有定义但会预先传入的对象或方法,比如window, document, location, fetch等等。我们知道其实document, location, fetch这些东西都在window上,window是一个上下文。 在iframe中也有自己的window,各自独立。而在nodejs,怎么形成这个"window"呢,这就需要vm来提供。
我们看到nodejs通过require也能运行其他模块,这是因为它们用到vm中的方法。
Safeify node vm沙盒实现
const vm = require('vm'); const script = new vm.Script('m + n'); const sandbox = { m: 1, n: 2 }; const context = new vm.createContext(sandbox); script.runInContext(context);
频繁创建和销毁线程对性能的影响显而易见,同时这样的设计并不能撑其瞬时峰值流量。 线程池就是进行线程的生命周期管控,达成=》线程复用
libuv threadPool 源码地址=》 源码地址
线程池利用死循环让线程无法结束,在等待任务期间处于阻塞状态,利用阻塞唤醒来让线程接收任务(本质上阻塞唤醒基于信号量),从而达到线程复用,结束当前任务后进入下一次循环,周而复始。
eventloop + 线程池 = 异步非阻塞
可爱的你发起了一个 IO 调用,从 《大前端进阶 Node.js》系列 异步非阻塞中讲过,一个 IO 调用要么是阻塞调用,要么是先非阻塞的发起 IO,再在需要看结果的时候阻塞的去获取,显然这两种模式都不是我们想要的。
我们要的是异步非阻塞,所以这个 IO 调用一定不是在主线程中执行,这个时候我们就能联想到上面的线程池。
主线程不能被阻塞,但线程池里面的线程可以,主线程只需要把 IO 调用交给线程池来执行,自己就可以愉快的玩耍,以此达到了我们的第一个目标:非阻塞。
在线程池 IO 处理结束后,会主动的把结束的请求放入 eventloop 的观察者(watcher)中,也就是我们的 queue 中,eventloop 处于不断循环的状态,当下一次循环 check 到 queue 里有请求的时候,就会取出来然后执行回调,这样我们想要的异步就达到了。
最终通过线程池和 eventloop 结合,呈现出的效果就是,当你发起一次 IO 调用,你无需阻塞的等待 IO 结束,也无需在想利用 IO 结果的时候不断的轮询,整个 IO 过程对主线程而言非阻塞,并且自动结束时执行回调,达到我们想要的异步非阻塞。
核心总结:Node 利用线程池来执行 IO 调用,避免阻塞主线程,执行结束后把结果和请求放入一个队列,利用事件循环来取出队列的请求,最后执行回调,达到了异步非阻塞的效果。
在抢单系统中,前端页面如若面临成千上万个需求,需要做的是限制用户频繁出发请求事件。对触发事件进行节流固然可以,但直接拿接口来发送请求,这个时候我们要防止恶意触发,需要做好防csrf攻击(跨站点请求伪造)。
Set-Cookie: key=value; SameSite=Strict
当我们做一个抢单系统的时候,面对成千上万个请求首先考虑的,便是怎么分担服务器的压力,这时候负载均衡
Referer这个http header的参数应用得当的话,是可以提高安全性的,比如,可以这个参数其实就告诉了链接的请求来源于哪个网站,所以可以根据这个特性,限制一些接口只能本网站的才能调,外部网站不能调
Referrer-Policy: origin
<meta name="referrer" content="origin">
<a href="..." referrerpolicy="origin" target="_blank">xxx</a>
URLSearchParams
手动实现
PWA
What are Progressive Web Apps?
node中的vm
nodejs有一个叫vm的模块,这是用来运行代码的模块。怎么说呢,我们知道浏览器只要你将代码放在script标签中,或script src远程引用它,代码就会执行,这些代码会执行一些我们没有定义但会预先传入的对象或方法,比如window, document, location, fetch等等。我们知道其实document, location, fetch这些东西都在window上,window是一个上下文。 在iframe中也有自己的window,各自独立。而在nodejs,怎么形成这个"window"呢,这就需要vm来提供。
我们看到nodejs通过require也能运行其他模块,这是因为它们用到vm中的方法。
Safeify node vm沙盒实现
【nodejs】eventloop + 线程池
线程池
频繁创建和销毁线程对性能的影响显而易见,同时这样的设计并不能撑其瞬时峰值流量。 线程池就是进行线程的生命周期管控,达成=》线程复用
libuv threadPool 源码地址=》 源码地址
线程池利用死循环让线程无法结束,在等待任务期间处于阻塞状态,利用阻塞唤醒来让线程接收任务(本质上阻塞唤醒基于信号量),从而达到线程复用,结束当前任务后进入下一次循环,周而复始。
可爱的你发起了一个 IO 调用,从 《大前端进阶 Node.js》系列 异步非阻塞中讲过,一个 IO 调用要么是阻塞调用,要么是先非阻塞的发起 IO,再在需要看结果的时候阻塞的去获取,显然这两种模式都不是我们想要的。
我们要的是异步非阻塞,所以这个 IO 调用一定不是在主线程中执行,这个时候我们就能联想到上面的线程池。
主线程不能被阻塞,但线程池里面的线程可以,主线程只需要把 IO 调用交给线程池来执行,自己就可以愉快的玩耍,以此达到了我们的第一个目标:非阻塞。
在线程池 IO 处理结束后,会主动的把结束的请求放入 eventloop 的观察者(watcher)中,也就是我们的 queue 中,eventloop 处于不断循环的状态,当下一次循环 check 到 queue 里有请求的时候,就会取出来然后执行回调,这样我们想要的异步就达到了。
最终通过线程池和 eventloop 结合,呈现出的效果就是,当你发起一次 IO 调用,你无需阻塞的等待 IO 结束,也无需在想利用 IO 结果的时候不断的轮询,整个 IO 过程对主线程而言非阻塞,并且自动结束时执行回调,达到我们想要的异步非阻塞。
核心总结:Node 利用线程池来执行 IO 调用,避免阻塞主线程,执行结束后把结果和请求放入一个队列,利用事件循环来取出队列的请求,最后执行回调,达到了异步非阻塞的效果。
系统架构
前端层面
在抢单系统中,前端页面如若面临成千上万个需求,需要做的是限制用户频繁出发请求事件。对触发事件进行节流固然可以,但直接拿接口来发送请求,这个时候我们要防止恶意触发,需要做好防csrf攻击(跨站点请求伪造)。
Nginx层
当我们做一个抢单系统的时候,面对成千上万个请求首先考虑的,便是怎么分担服务器的压力,这时候负载均衡
referer-policy
Referer这个http header的参数应用得当的话,是可以提高安全性的,比如,可以这个参数其实就告诉了链接的请求来源于哪个网站,所以可以根据这个特性,限制一些接口只能本网站的才能调,外部网站不能调
请求头中
meta标签
a标签