Concurrency
众所周知,浏览器发起的请求最大并发数量有限制,这是因为浏览器会限制同一域名下的并发请求数量,以避免对服务器造成过大的压力。
模拟一下大量请求的场景
12345678const ids = new Array(100).fill('')console.time()for (let i = 0; i < ids.length; i++) { console.log(i)}console.timeEnd()
一次发送上百次请求,虽然浏览器有队列机制(上图pending),但是我们还是需要细颗粒度的控制并发请求。
解决思路:请求池利用Promise模拟任务队列,从而实现请求池效果
step 1:定义请求池主函数1234export const handQueue = ( reqs // 请求数量) => {}
接受一个参数reqs,它是一个数组,包含需要发送的请求。函数的主要目的是对这些请求进行队列管理,确保并发请求的数量不会超过设定的上限。
step 2:定义 dequeue函数12345678910111 ...
Twitter(X)分享问题
Twitter(X)分享机制当你分享数据到 twitter 网站,会有爬虫机器人一直读取并且解析你的网站数据(meta 标签),所有要怎么让你的 meta 标签被读取呢?
首先我们会想到动态改变 meta 标签,由于我们是 spa 应用,所以在通过 js 动态解析是行不通的。
曲线救国https://twitter.com/intent/tweet?text=${text}&url=${url}
其中 text 是分享文案,url 是具体的分享链接
如果仅仅是分享一个链接的需求,以上即可满足!但是需求往往是需要图文视频结合的。
如下是 twitter 爬虫会抓取的 meta 数据,支持文字、图片和视频:
123456789101112<meta name="twitter:card" content="summary_large_image" /><meta name="twitter:site" content="@nytimes" /&g ...
竞态问题
什么是竞态问题
竞态问题,又叫竞态条件(race condition),它旨在描述一个系统或者进程的输出依赖于不受控制的事件出现顺序或者出现时机。
此词源自于两个信号试着彼此竞争,来影响谁先输出。
简单来说,竞态问题出现的原因是无法保证异步操作的完成会按照他们开始时同样的顺序。举个🌰:
有一个分页列表,快速地切换第二页,第三页;
先后请求 data2 与 data3,分页器显示当前在第三页,并且进入 loading;
但由于网络的不确定性,先发出的请求不一定先响应,所以有可能 data3 比 data2 先返回;
在 data2 最终返回后,分页器指示当前在第三页,但展示的是第二页的数据。
这就是竞态条件,在前端开发中,常见于搜索,分页,选项卡等切换的场景。
那么如何解决竞态问题呢?在以上这些场景中,我们很容易想到:
当发出新的请求时,取消掉上次请求即可。
而我发现意识到问题是在轮询请求的时候,发现页面出现一闪而过的不协调
取消过期请求XMLHttpRequest 取消请求XMLHttpRequest(XHR)是一个内建的浏览器对象,它允许使用 JavaScript 发送 HT ...
浅谈EXPO
首先让我吐槽一下,身为一位 web 开发人员处理 xcode 构建和 native deps 等问题是真的无奈!!
Expo vs RnExpo 和 React Native 是两个密切相关的工具,用于开发跨平台移动应用,但它们在使用方式和灵活性上有所不同。下面是对它们的详细介绍和对比:
React NativeReact Native 是一个由 Facebook 开发的开源框架,允许开发者使用 JavaScript 和 React 构建原生移动应用。React Native 提供了一组原生组件,这些组件被渲染为原生视图,而不是 Web 视图。
优点:
跨平台开发:一次编写,可以在 iOS 和 Android 上运行。
性能好:使用原生组件,性能接近原生应用。
大社区和丰富的生态系统:有很多开源库和工具可以使用。
灵活性:允许深度访问原生功能和第三方原生模块。
缺点:
设置复杂:初学者可能需要花费更多时间来设置开发环境。
原生代码需求:有时候需要编写原生代码来实现特定功能。
升级困难:随着 React Native 版本的升级,应用维护可能变得复杂。
ExpoExpo 是一 ...
Node.js 事件循环
Node.js 事件循环,定时器和 process.nextTick()什么是事件循环?事件循环是 Node.js 处理非阻塞 I/O 操作的机制——尽管 JavaScript 是单线程处理的——当有可能的时候,它们会把操作转移到系统内核中去。
因为目前大多数内核都是多线程的,所以它们可以在后台处理多种操作。当其中的一个操作完成的时候,内核通知 Node.js 将适合的回调函数添加到 轮询 队列中等待时机执行
事件循环机制解析当 Node.js 启动后,它会初始化事件循环,处理已提供的输入脚本(或丢入 REPL,本文不涉及到),它可能会调用一些异步的 API、调度定时器,或者调用 process.nextTick(),然后开始处理事件循环。
下面的图表展示了事件循环操作顺序的简化概览。
123456789101112131415161718 ┌───────────────────────────┐┌─>│ timers ││ └─────────────┬─────────────┘│ ┌─────────────┴──────── ...
异步钩子-异步上下文存储
Asynclocalstorage此类创建通过异步操作保持一致的存储。
虽然你可以在 node:async_hooks 模块之上创建自己的实现,但 AsyncLocalStorage 应该是首选,因为它是一种高性能且内存安全的实现,涉及实现起来并不明显的重要优化。
以下示例使用 AsyncLocalStorage 构建一个简单的记录器,它为传入的 HTTP 请求分配 ID,并将它们包含在每个请求中记录的消息中。
1234567891011121314151617181920212223242526272829import http from 'node:http';import { AsyncLocalStorage } from 'node:async_hooks';const asyncLocalStorage = new AsyncLocalStorage();function logWithId(msg) { const id = asyncLocalStorage.getStore(); console ...
异步钩子
术语异步的资源表示具有关联回调的对象。 此回调可能会被多次调用,比如 net.createServer() 中的 'connection' 事件、或者像 fs.open() 一样只调用一次。 资源也可以在调用回调之前关闭。 AsyncHook 没有明确区分这些不同的情况,而是将它们表示为抽象的概念,即资源。
如果使用 Worker,每个线程都有一个独立的 async_hooks 接口,每个线程都会使用一组新的 async ID。
API概述123456789101112131415161718192021222324252627282930313233343536373839404142434445import async_hooks from 'node:async_hooks';// Return the ID of the current execution context.const eid = async_hooks.executionAsyncId();// Return the ID of the handle responsible ...
异步资源
AsyncResourceAsyncResource 类旨在通过嵌入器的异步资源进行扩展。 使用它,用户可以轻松触发自己资源的生命周期事件。
init 钩子将在实例化 AsyncResource 时触发。
以下是 AsyncResource API 的概述。
12345678910111213141516171819202122232425import { AsyncResource, executionAsyncId } from 'node:async_hooks';// AsyncResource() is meant to be extended. Instantiating a// new AsyncResource() also triggers init. If triggerAsyncId is omitted then// async_hook.executionAsyncId() is used.const asyncResource = new AsyncResource( type, { triggerAsyn ...
浅谈 ahooks
ahooks一套高质量可靠的 React Hooks 库
ahooks 函数处理规范
所有输入函数永远使用最新的(useRef 缓存)
针对输入函数,通过 useRef 做一次记录,以保证在任何地方都能访问到最新的函数。
12const fnRef = useRef(fn)fnRef.current = fn
比如 useUmount 代码如下:
1234567891011const useUnmount = (fn) => { const fnRef = useRef(fn) fnRef.current = fn useEffect( () => () => { fnRef.current() }, [] )}
所有的输出函数地址都不会变化 (useMemo/useCallback/useMemoizedFn)
举个例子,假设有个自定义 hook useToggle ,其代码如下:
123456789101112// 自定义hook useTogglefunction useT ...
npm version
npm version123npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]alias: verison
npm version from-git 命令获取最新最新的tag(git describe)
下面是关于版本选项的描述(假设默认版本为0.2.0):
选项
描述
例子
说明
major
重大更新版本
npm version major
0.2.0 =》1.0.0
minor
主要更新版本
npm version minor
0.2.0 =》0.3.0
patch
补丁更新版本
npm version patch
0.2.0 =》0.2.1
premajor
重大更新预发布版本
npm version premajor
0.2.0 =》1.0.0-0
preminor
主要更新预发布版本
npm version preminor
0.2.0 =》0.3.0-0
prep ...