如何实现 Promise
先来看下 Promise 的常见应用: 观察者模式观察上面的这个例子,我们来分析 Promise 的调用流程: 构造方法接受一个 executor 函数,在 new Promise 的时候这个 executor 立即执行 executor 内部的异步任务被放入微任务队列等待执行 then 被执行,收集成功/失败回调,放入成功/失败队列 executor 的异步任务被执行,触发resolve/reject,从成功/失败队列中取出回调依次执行 由上面的分析得知这是一种典型的观察者模式。这是典型的“收集依赖->触发依赖->取出依赖执行”的方式,在 Promise 中执行顺序是 “then收集依赖->异步触发resolve->resolve执行依赖”。由此我们可以勾勒出 Promise 的大致形状: 123456789101112131415161718192021222324252627282930class Promise{ constructor(executor){ ...
一些好用的轮子和工具
凡是现实的都是合理的,凡是合理的都是现实的。—— 黑格尔 canvas绘图阿里的数据可视化的底层框架g2,无需从头到尾操作原生canvas api了,画线、矩形、圆形、贴图等非常便利。 提高效率的chrome拓展 双向修改CSS的工具livestyle 常见的网关 Openresty:基于 Nginx 的高性能 Web 平台,集成了大量模块,用来处理 HTTP 请求,被许多企业作为内部网关的基础框架 Kong:构建在 OpenResty 上的网关平台,有丰富的插件体系,支持身份认证、限流、日志记录、监控等功能 大模型 从 0 开始写大模型 基于 AI 的浏览器自动化 githubgithub...
一些生活技能
我当然不喜欢贫穷,人穷志短,成天为衣食住行操心是很毁人的。但我从不梦想着大富大贵,因为人一旦把赚钱当作目的,就永远也不会觉得够。富了终归可以更富,走上这条路的人,很少能够自己停下来。有大量触目惊心的权钱交易的案例已经证明,对金钱的贪欲会使人不顾一切,甚至不要性命。千万不要以为,这些一失足成千古恨的人是天生的坏人。事实上,他们与我们中间许多人的区别只在于,他们恰好处在一个直接面对巨大诱惑的位置上。赚多少钱是个够?永远也没够!不管是谁,赚钱的目的,不过是为了更幸福。但有时候,我们走得太远,慢慢忘记了为什么出发。 健身食材香蕉 燕麦 鸡胸 鸡蛋...
Koa 源码解析
Context 上下文对象ctx -> Koa Contextctx.req -> req -> IncommingMessagectx.res -> res -> ServerResponse ctx.req 是 node 原生的,ctx.request 是 koa 封装的请求对象,提供了更高级的 API 和更友好的方法(内部实现是 ctx.req) 在 lib/context.js 中: 12345678910111213141516171819202122232425262728293031323334/** * Request delegation. */delegate(proto, 'request') .method('acceptsLanguages') .method('acceptsEncodings') .method('acceptsCharsets') .method('accepts') ...
消息推送系统的设计与实现
所有真理的成长都需要经过 3 个阶段:首先是遭到无情地嘲笑,然后是激烈地反对,最终被当成理所当然所接受。 弹幕系统的技术挑战技术复杂度系统调用的瓶颈以一个直播间为例,假设在线人数为 100W,每秒发送的弹幕数量为 1000 条,据此可以推算出单个直播间的吞吐量要达到 100W * 1000条 = 10亿条/秒,把问题延伸到 N 个直播间,则系统的吞吐量为 N*10亿/秒。 根据经验值,Linux 系统在处理 TCP 网络调用的时候大概每秒只能处理 100W 左右的包,这么看的话发送一条弹幕就达到了单机的处理能力上限,这是第一个难点。 解决:假设在线人数为 100W,推送 1 条消息就达到了系统极限,假设推送 100 条消息仍旧使用单机处理,如何优化呢?很简单:将 100 条消息合并成 1 条消息进行发送,这样对于 100W 人在线的系统推送吞吐量固定为每秒 100W 次。当然合并消息不可能无限大,当超过一定阈值之后,TCP/IP 层会进行大包拆分,此时底层实际包频就会超过每秒 100W...
秒杀系统的设计与实现
特征与难点 写强一致性:抢购商品的时候不能出现超卖现象 读弱一致性:可能读到有库存,但是实际下单会失败 抢购人数远多于库存,读写并发巨大 库存少导致有效写少(真正形成订单的比较少) 难点在于极致性能的实现以及高可用的保证。 高并发下,某个小依赖可能直接造成雪崩 流量预估难精确,过高也造成雪崩 分布式集群,机器多,出故障的概率高 秒杀原理 合理利用 CDN:例如订单详情页,有效减少回源流量 Nginx 限流:过载保护 异步队列:高并发的流量 -> 均匀的流量 Nginx 负载均衡:接入层分摊流量到无状态 service 层提供服务 CDN原理 用户输入访问的域名,操作系统向 LocalDns 查询域名的ip地址. LocalDns向 ROOT DNS 查询域名的授权服务器(这里假设LocalDns缓存过期) ROOT DNS将域名授权dns记录回应给 LocalDns LocalDns得到域名的授权dns记录后,继续向域名授权dns查询域名的ip地址 域名授权dns查询域名记录后(一般是CNAME),回应给...
短地址服务的设计与实现
有不少网站可以提供长链转短链的服务,例如新浪短地址服务、bitly。背后的原理其实是将长链和短链进行一一映射。换而言之,各家短链服务商的短链和长链是一一对应的。其中的关键点在于如何根据长链生成短链,以及当用户访问短链后怎么处理。 如何生成短地址比较直观想到的解法是使用哈希函数,但是无论怎样构造哈希函数,都存在哈希碰撞的问题。再次想到碰撞之后可以在 hash 字符串后面补充其他字符串来实现,但是需要补充多少位呢?这种方案显然不是那么方便。联想到全局唯一,以及数据存储我们很容易想到数据库的自增 id,其实这样也是可以的,这里为了实现简单(主要是天然的过期时间),采用了 redis 来存储数据,其 key 设计如下: globalId:全局自增 id,用于保证短链的唯一性shortToLong:短地址到长地址的映射,key...
面试常用套路
墨菲定理:任何事情都没有表面看起来那么简单;所有的事情都会比你预估的时间长;会出错的事情总会出错;你总是担心的事情,它总会发生的。 如何规范写日志日志要有分隔符大多数时候使用|作为分隔符。分析数据的时候直接用分隔符拆分对应的字段和属性。 123456# 正确例子类名|方法名|输入参数|输出参数# 错误例子1(不用分隔符)类名方法名输入参数输出参数# 错误例子2(用多种分隔符)类名#方法名 输入参数|输出参数 通过UUID编号来保证日志的连贯性每次请求都应该有一个唯一编号,每记录一次日志还应该有一个唯一编号。例如: 12api.ERROR: 79a8ea37dceff105|0|responseObj is error:{"return_code":"SUCCESS","return_msg":"OK"}api.ERROR:...
深入理解 HashMap
原理HashMap的底层采用的散列算法是拉链法(另一种散列算法是线性探测法)。并且在JDK1.8中使用红黑树对长链表进行优化。 初始容量、负载因子、阈值初始容量比较好理解,阈值指的是当桶的个数超过了这个值后Hash表会进行扩容。 12345678910/*** The next size value at which to resize (capacity * load factor).** @serial*/// (The javadoc description is true upon serialization.// Additionally, if the table array has not been allocated, this// field holds the initial array capacity, or zero signifying// DEFAULT_INITIAL_CAPACITY.)int...
情人节有感
...