
import { once, EventEmitter } from 'node:events'; import process from 'node:process'; const ee = new EventEmitter(); process.nextTick(() => { ee.emit('myevent', 42); }); const [value] = await once(ee, 'myevent'); console.log(value); const err = new Error('kaboom'); process.nextTick(() => { ee.emit('error', err); }); try { await once(ee, 'myevent'); } catch (err) { console.error('error happened', err); } 以上代码来自这里
里面涉及到的基础知识点有:
Promiseasync/awaitnexttick 队列EventEmitter最后,这真的不算八股,AI 当然可以解释清楚,但这么一段简单清晰的代码,你还不知所以然的话,那对着 Vibe Coding 出来的屎山,最后只能束手无策了。
]]>现在发现双等号直接可以帮你转类型后再比较。
甚至可以这么用: if (a == 0) { ... }, 这里当 a 是 0 / "" / false 时候都成立。
看到很多项目都把双等号给禁了( eslint eqeqeq ),没仔细研究,但有些情况下还是不错的。
]]>来历不明,有点可疑
]]>我通常是
if (a) {...} 但是会遇到数字 0 的情况,那就是
if (a !== null && a !== undefined) {...} 然后想着是不是要封装一个isEmpty函数 请问需要封装吗?
webpack -> electron-builder -> 构建 PKG 再通过 altool 上传到 appstoreconnect
全部都可以通过脚本方式自动化,唯一需要手动修改的就是版本号和打包的号。
但是移动端就很麻烦,每次打包前端同步到框架后,需要运行 xcode 来进行修改版本号和归档,然后还需要手动点击上传非常的繁琐,请问这部分各位大佬是如何处理的,如何自动化最后这个 capacitor 框架的打包上传步骤而不用打开 Xcode 。
]]>还看到了一篇锁的文章,感觉很类似我遇到的这个问题: https://jackpordi.com/posts/locks-in-js-because-why-not
伪代码如下:
let isRefreshing = false // 标记是否正在刷新 token let requests: Array<(token: string, err?: string) => void> = [] // 需要重试的请求列表 client.interceptors.response.use((response: AxiosResponse) => { const { config, status } = response const { code } = response.data if (status >= 500) { return Promise.reject("服务器错误") } else if (code == 10003) { // access token 过期,尝试刷新 token const { refreshToken } = user.useLoginStore.getState() if (refreshToken) { // FIXME: ?? 存在并发读取 isRefreshing 为 false 导致发出多次刷新 token 的请求 if (!isRefreshing) { isRefreshing = true return refreshToken() .then(({ data }) => { const { code } = data if (code === 10000) { user.useLoginStore.setState((state) => { state.token = data.data.token }) config.headers["Authorization"] = data.data.token const retry = client(config) requests.forEach((cb) => cb(data.data.token)) requests = [] return retry } else { return Promise.reject(data.message) } }) .catch((err) => { const msg = isError(err) ? err.message : err requests.forEach((cb) => cb("", msg)) requests = [] publishInvalidTokenEvent(msg) }) .finally(() => { isRefreshing = false }) } else { return new Promise((resolve, reject) => { requests.push((token: string, err?: string) => { if (err) { reject(err) } else { config.headers["Authorization"] = token resolve(client(config)) } }) }) } } else { requests.forEach((cb) => cb("", "登录过期") requests = [] publishInvalidTokenEvent("登录过期") } } else if (code === 10000) { return response.data.data } else if (code == 10006) { // 长 token 失效 requests.forEach((cb) => cb("", "登录过期") requests = [] publishInvalidTokenEvent("登录过期") } else { return Promise.reject(response.data.message || response.data.msg) } }) ]]>一个处理数字显示问题的 JS 库。
尤其是在处理有小数点的数字时会很有用。
]]><audio controls> <source src="data:audio/mpeg;base64, base64-encoded-string" type="audio/mpeg"> </audio> 重新解码作为 blob 播放,放出来就很多杂音,这中情况是哪里的问题?
<script type="text/Javascript"> const audioCOntext= new (window.AudioContext || window.webkitAudioContext)(); const decoder = new TextDecoder("utf-8"); function base64ToArrayBuffer(base64) { const binary = atob(base64); const len = binary.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = binary.charCodeAt(i); } return bytes.buffer; } function playAudioChunk(base64) { const arrayBuffer = base64ToArrayBuffer(base64); audioContext.decodeAudioData(arrayBuffer).then((audioBuffer) => { const source = audioContext.createBufferSource(); source.buffer = audioBuffer; source.connect(audioContext.destination); source.start(0); }).catch((err) => { console.error("Error decoding audio data", err); }); } // ws-connection ... playAudioChunk(base64-encoded-string); </script> ]]>document.write() 方法的 Bookmarklet ,但是在这个网站中无法正常使用,具体表现总是抛出错误 Uncaught TypeError: Cannot read properties of undefined (reading 'write')。 已尝试通过新建 iframe 获取干净的 write 方法并绑定到顶层 document ,依旧无效。问 AI 也没有提供可行的解决方案。
个人水平实在是有限,求助高手帮忙看看这网站用了什么魔法阻止使用这个方法,有解决的可能吗?
]]>比如售后如何在订单系统里找到有问题单,怎么从别的页面复制一些参数填表,给用户点一下退款这种简单的事都能问半天。
有没有技术,能实现你问 AI 如何操作 XXX ,AI 在页面上依次给你把步骤圈出来,先点 A 再输入 B 再选 C 这样。
用知识库录入操作手册感觉有局限性,因为系统界面可能改版之后导致某些入口和按钮变了,知识库跟不上
AI 能不能直接通读一遍页面结构,大致摸清楚所有地方的功能按钮怎么对应的,然后对操作使用指南进行回答?
最好直接在页面上给他圈出来,每一步点哪里,高亮爆闪一下;类似游戏上手教学关卡一样。
这种技术一般怎么搭建呀?大家有什么思路不。
]]>需求:买了个小米的摄像头,不支持 ONVIF ,但是当视频录制到 128M 就形成文件,支持存到 smb 上,想写个 web 页面方便查看。后端 express ,前端 vue3 。简单说就是播放一堆 mp4 文件。
实现:视频录制格式是 hvc1+opus 。
1 ,开始用 video 来播放没问题。copilot 帮助下很快前后端搭起来,可以根据日期选择播放视频文件。
2 ,考虑安全,前后端都加了 jwt 认证,但是 video 请求视频文件不支持带 headers.Authorization token 。
3 ,咨询 copilot ,推荐转成 blob ,这样可以了带认证了,但是 blob 必须一次把 128M 都读回来才能播放。
4 ,再咨询 copilot 如何分片,推荐了 mediasource 配合 range ,实现快速播放。
5 ,copilot 再次提示 chrome 的 mediasource 实现不支持 hvc1 ,果然 chrome 提示不支持的类型;换了 safari 的确是可以不缓冲直接播放了。
6 ,copilot 建议在后端 ffmpeg 转码以后再推出来,可是后端只是台 J1900 ,转 4k 的码比播放速度还慢。这条路也不通。
7 ,copilot 又推荐了 m3u8 的切片方法,看起来挺复杂了,感觉搞不定。
现在只有退回原点,取消认证,直接用 video 播放。看看 copilot 的帮扶道路,你说他没用吧,后面每个知识点都是现学的,但是最后还是没解决问题。
]]>apps 和 packages 目录,开发者可按规范贡献代码,采用 MIT 许可证开源,欢迎反馈共创更好的 AI 桌面工具。 ]]>问题:因为考虑到移动端输入框 输入、触碰点击和 pc 端的操作不同。例如边输入变搜索,下拉框遮挡问题...
有没有大佬有方案,感谢
]]>我正在开发一个上位机的工具,是用 tcp 进行连接的。连接完了之后我会接收到数据,格式如下:
demo:>1,2,3 demo:>5,6,7 我需要对上面的数据进行解析组成每个通道的数据(通道由每一列元素),如上所示就是有 3 个通道[1,5], [2,6], [3,7]。 然后需要实时的绘图,最大的问题是,这个连接数返回的数据很大约 1s 有 1w 行的数据量。我要怎么进行一个比较好的数据绘图呢。
]]>const ps = new Promise(function name(resolve, reject) { let i = 0; while(i<1000000){ i = i+1; console.log('i=',i); } }); console.log('promise 是异步吗?');
等上面这 100 万次循(最耗时的操作)环执行完,我还有必要通过 then 去指定回调函数吗?我直接执行回调函数就可以了,根本不需要通过 then 去执行回调函数。
]]>
]]>我去谷歌 bug 网站也看到有人提了几个了, 哪位大佬知道是啥情况不
]]>我感觉常用的也就 map 和 filter 那几个,剩下的面试官也不给提示,发现候选者回答那么几个就直接下一题了。
像 join ,pop ,push 我感觉面试官愿意提这个单词甚至就简单描述一下场景,比如我有个先进后出的栈,我想入栈和出栈,可以用什么 array 方法,候选者完全能答上来的。
感觉问点 promise 代码题都比这个好,感觉今年几个面试好像完全都不考 promise 了....
]]>
)之前很早有做过跟 gpt 对话的插件 也加了语音识别 但是做不到戴上耳机后的自由对话 经常会自动中断
]]>下面是 demo 代码: https://codepen.io/Asn-La/pen/RNbvYjY
]]>React 使用率高达 82% ,第不知道多少次卫冕冠军。Vue 和 Angular 并列第二,各 50%。,Svelte 26%,剩下的都很低(同一个程序员可能用过多个框架,所以总和超过 100%)。
收入方面,各个框架的 JS 程序员平均年薪在 7 万美元。唯独 Vue 程序员最低,只有 5 万美元。
还有其他很多的结果,比如全栈框架、后端、打包工具、跨平台工具等等,感兴趣可以看看 https://2024.stateofjs.com/ 。以后技术选型也有参考。
]]>一个具有较高可扩展性的 JS AMD 规范模块加载器 partic2-iamdee
Github
Gitee
在上面的基础上做了个早期形态的“全栈”包管理 pxseed ,并附带一个 Javascript Notebook 。
Github
Gitee
纯网页模式 Javascript Notebook 演示地址
Github Pages
之前 V 站大佬推广的平台 帽子云
在知道 Typescript 之前不习惯写 JS 的,然后接触到 Typescript 的时候第一个问题就是模块化的问题,当时比较多的模块化方案就是 CommonJS 和 AMD 了,为了在浏览器上用自然用的是 AMD 。虽然有 webpack 了但是 AMD 更简单,然后一直用到了现在。
到了现在已经出现了很多前端构建工具,但遗憾的是,Javascript 还是没有一个扩展性较强的统一的模块机制。
例如 Node ,早期用的 CommonJS ,现在开始转变为 ES Module ,浏览器都支持了 ES Module ,但是各种打包工具又会在打包后使用不同的加载方式。而且还有个特例-ServiceWorker 中不支持 ES Module 中的动态 import 。
同时,可能是照顾到打包工具等实现,ES Module 的可扩展性非常弱,可能只有 Import maps 改变映射这种级别的扩展。例如我想从内存/IndexedDB 中加载模块,ES Module 就不能支持。
同时我也接触了 Jupyter Notebook/Lab ,觉得是个很方便的平台,可以动态的执行 Python 并查看每一步的结果。于是也想在 JS 上实现个类似的东西,虽然有 IJavascript ,但是我想有能不依赖后台 python 的这么一个东西。
然后就有了做包管理的想法。
NPM 分发和获取的经常是编译产物。可以对比下 Golang 。Golang 虽然槽点不少,但包管理工具链还是比较优秀的。分发的是源码,对某个函数有疑问,可以在 IDE 中跟进源码,NPM 上则大多只能跟到类型声明。
Node/NPM 的设计对比 python/PIP 有一些地方对 Notebook 不太友好,PIP 默认装全局,NPM 默认装项目文件夹,当然 NPM 的设计一定程度解决了版本问题,不过我的观点是版本问题还是需要第三方库本身做好,包管理来处理兼容问题多少会有一些难以解决的 corner case 。
因此我尝试做了这个 pxseed“全栈”包管理,在这个框架下,前端浏览器和后端 Node 都可以用一套编译产物,并用 AMD 加载模块,Typescript 源码直接分发和下载,这样 IDE 里点一下可以跟进到源码。为了兼容 NPM 生态,pxseed 也添加了 Rollup 来打包 NPM 模块为 AMD 供前端使用。
当然 AMD 做前端是有致命缺点的,AMD 加载零碎文件的性能差,没有 Tree-Shaking ,没有 SEO 。但如果是想做成个类似 python 的属于 JS 的全栈包管理本地用,还是挺不错的。而且 partic2-iamdee 高度可定制化,也让优化上述问题成为可能,比如,你也可以用 Websocket 来加载 JS 模块。
当然这些东西都有点"路子野",说不定已经早有人做过更好更成熟的实现方案,如果有的话欢迎推荐给我。
]]>console.log('Hello') 输出 echo Hello ]]>video = document.querySelector("#vidplayer > video") 大概像这样。但是发现这个网站很神奇的一点是,如果打开新网页直接在控制台输入这句命令,是获取不到 video 的,必须先经过审查元素的这一步,才能在控制台里获取到。
体感上这像是只有进入审查元素了,才会动态生成相关元素,但是进入之前也能使用播放功能,感觉非常神奇。请问有没有老哥懂得这是什么原因呢
对 js 接触得很浅,可能是很粗浅的问题,希望大家不吝赐教
]]>我的工作内容有写网页游戏,游戏涉及到前后端通信,没找到顺手的通信包,所以手写了一个通用的 js 通信包:remote。
js 子集iframe / Java 服务器 等 // 远端 remote.register('something', async (params: Whatever) => { return WhatYouWant }) // 本地 // res === WhatYouWant const res = await remote._.something(xxx) 由于通信双方是平等的,所以 B 调用 A 的流程也是一样的

]]>
def cid_hash_file(path): h = hashlib.sha1() size = os.path.getsize(path) with open(path, 'rb') as stream: if size < 0xF000: h.update(stream.read()) else: h.update(stream.read(0x5000)) stream.seek(int(size/3)) h.update(stream.read(0x5000)) stream.seek(size-0x5000) h.update(stream.read(0x5000)) return h.hexdigest().upper() 上面的代码用 chatGPT 转换后是这样的
function cidHashFile(path) { const h = crypto.createHash('sha1'); const size = fs.statSync(path).size; const stream = fs.createReadStream(path); if (size < 0xF000) { stream.on('data', (chunk) => { h.update(chunk); }); } else { stream.on('data', (chunk) => { if (stream.bytesRead <= 0x5000) { h.update(chunk); } else if (stream.bytesRead >= Math.floor(size / 3) && stream.bytesRead < Math.floor(size / 3) + 0x5000) { h.update(chunk); } else if (stream.bytesRead >= size - 0x5000) { h.update(chunk); } }); } stream.on('end', () => { const result = h.digest('hex').toUpperCase(); console.log(result); }); stream.on('error', (err) => { console.error('File reading error:', err); }); } 试了不同文件计算出来的 hash 不一致,有没有大佬知道原因的?
]]>昨天突发奇想,想到另一个方案,这个方案我测试在 node 和 chrome 上是可行的。 就是借助 new Function 自定义一个带标记的函数,就可以将标记的函数名插入到 new Error().stack ,就可以区分当前的任务栈,实现 task local,继而也可以通过 hook promise 实现 async 函数中止。虽然和最早方案的表现有一些差异。这个方案经过测试确实是可行的。
但是这个方案只在 V8 测试是生效的,在 txiki.js(quickjs)上 await 的堆栈会丢失。并且在获取当前 task 时有较高的性能损耗,所以只能说仅供参考,没什么实际应用价值
]]>项目使用腾讯云点播服务进行视频内容分发。需要实现前端视频流量监控功能,当用户观看视频消耗的流量达到特定阈值时,自动终止视频播放。同时会将相关数据记录到数据库,为统计页面做准备。
performance.getEntriesByType('resource') 获取视频资源的 transferSizetransferSize 始终返回 0 ,无法获取实际流量数据但是目前的实现方式是 根据 video 播放的进度,找到对应的词条的 dom 高度,向上调整若干 offsetTop ,挺原始的方式
油管字幕内容是一个类似 xml 格式的文件,从内容上看,应该是把 script 直接丢到页面(或者某个容器)里头,没想明白这种方式是如何实现的。 文件大概长这样
]]>