第 22 话
date
Mar 17, 2023
tags
summary
type
Post
status
Published
slug
series-22
stream response (SSE)
最近使用了比较多的第三方 ChatGPT,这种文字流式输出的效果是必备的。在阅读 OpenGPT 这个项目的代码时,了解到具体的实现方式,这种方案叫做 SSE

// This server response data is a ReadableStream
const reader = data.getReader()
const decoder = new TextDecoder()
let done = false
while (!done) {
const { value, done: doneReading } = await reader.read()
done = doneReading
const chunkValue = decoder.decode(value)
setGeneratedResults((prev) => prev + chunkValue)
}
核心代码大概就是上面所示,接口返回一个“可读流”,用 Javscript 去不断的读取流中的文本再输出到页面上。
Raindrop 订阅
最近订阅了 Raindrop $28/年,之前犹豫了很久一直想用它这个 Pro 版本,最终还是先决定付费使用一段时间,以后不满意再退了,反正一个月 ¥16 钱也还好(可以先订阅一个月玩玩)。

我把所有一时间不知道怎么分类的收藏都丢到 Archive 文件夹里面了,能快速区分的导航类网页才分类出来(如公司测试环境、生产环境的地址),有些功能型或者快消类网络图片也丢上去,以后想要用到的时候就直接全文搜索 😹
期待 Raindrop 的全文搜索的实际使用效果,特别是中文模糊搜索能力。
因为使用了各种稍后读的应用,全文搜索能力没有一个特别满意的。

另外,不建议把“稍后读”和“书签”这两个东西放入一个工具里面来做管理。之前也是这么做过很长一段时间(都放在 Pinboard 里面)
最近的思考是,书签和文章不适合放到一处进行管理,它们两者的处理的工作流完全不同。
稍后读还是 Readwise Reader 或者源网站更好一点,Raindrop 我目前的定位更多的是收藏、导航和全文搜索(公网上的内容),图片里面的 Later 我命名也不太对,这里主要是别人的文章,感觉有时候需要时不时去警醒一下自己。

另外对于个人笔记来说,我的定位是 “私网内容”,不知道为什么我感觉还是存储在本地文件系统会更好一点,一来比较粗糙还没准备好分享,二来有些偏个人流水账没什么营养。目前我的用法是使用 Drafts(macOS/iOS)快速输入,之后感觉有些值得存档的内容就存储到本地文件系统,后续查看、搜索使用 Obsidian (macOS/iOS),而后续的编辑则是使用 vscode 编辑,缺点就是只能搜索纯文字。
obsidian 搜索:
- macOS: raycast plugin「obsidian」;obsidian plugin「Open vault in VsCode」 ;
- iOS:obsidian.app
Raindrop 全文搜索,使用下来暂时发现支持的功能:
- 只支持纯文字搜索,图片里的文字不支持搜索
- 支持搜索的文字,可断词检索(就是普通的文字搜索)
我目前使用的场景是,例如我前天看了完 DEX#xxx 周刊,然后直接丢到我的 Archive 文件夹里面,它里面有介绍到某个工具的关键字,今天我想搜索回来直接就可以搜索回来了(Twitter 里面回复的内容好像也可以)。


目前就这样先用着了,后面看情况再说,万一有其他替代方案呢。
部分 Excel 或者图片有时候我会放到 Google Drive 上面,然后使用 Raycast 里面的 Google Workspace 插件搜索打开(开会或者找同事的时候老是不知道在哪里 😹)

购买 OpenCat Pro

最近才看到的 Typescript 小技巧
感觉挺有意思的,TS 还可以这样搞
- A 页面使用某个 B 组件的 Props 类型,不用导出 B 组件的 Props Type
// B 组件
import React from 'react'
interface Props {
list: Record<string, any>[]
}
export default BComponent: React.FC<Props> = ({ list }) => {}
// A 页面
import React, { ComponentProps } form 'react'
import BComponent from '@/components/BComponent'
const APage = () => {
const books: ComponentProps<typeof BComponent>['list'] = [
{ id: 1, name: 'AAA' }
]
}
export default APage
- 使用 Exclude 可以排除某个类型(undefined、null 等)
// 例如:ProTable 组件的 Props 里面有一个 request 参数
request?: (
params: U & {
pageSize?: number;
current?: number;
keyword?: string;
},
sort: Record<string, SortOrder>,
filter: Record<string, (string | number)[] | null>
) => Promise<Partial<RequestData<T>>>;
// 我想在页面这样使用它,但是又不想自己重新写一边后续 request 的类型
// 例如 pageSize current、sort、filtter 等类型
// 然后我又希望可以使用 useCallback,这样可以获取最新的 params 或者 setParams
// 直接把 request 类型通过泛型入口给到 useCallback 是不行的
// 因为 useCallback 的类型是必须是函数,不能有 undefined,而 request 又有个 ?:
// 所以类型会是 (...) => Promise | undefined
import React, { useState, useCallback } from 'react'
const APage = () => {
const [params, setParams] = useState({ keyworkd: '' })
const listRequest = useCallback(async ({
current: page,
pageSize
}: {
current: number;
pageSize: number;
}) => {
const res = await getList({ ...params, page, pageSize })
}, [params])
return (
<ProTable
...
request={listRequest}
/>
)
}
// 这时候就可以使用 Exclude 排除 undefined 了(第二个参数是排除类型)
import React, { useState, useCallback } from 'react'
type TableRequest = Exclude<
ProTableProps<Record<string, any>, Record<string, any>>['request'],
undefined
>
const APage = () => {
const [params, setParams] = useState({ keyworkd: '' })
const listRequest = useCallback<TableRequest>(async ({
current: page,
pageSize
}) => {
const res = await getList({ ...params, page, pageSize })
}, [params])
return (
<ProTable
...
request={listRequest}
/>
)
}
OrbStack - Docker Desktop on Mac 的代替工具

周末玩玩 Swift UI

跟着这个台湾的小姐姐的新手教程,有问题问 ChatGPT
Github Copilot 免费平替: Codeium
D3.js 学习教程:D3 Start to Finish

在工作的项目中有一个网络连接可视化的地图,同事用的是 D3.js 来实现。就趁着这个机会来把 D3.js 学习一下。
Hueflake 一次为所有编辑器生成自定义主题颜色

通过拖动几个滑块就能生成出一个很棒的自定义主题颜色