首页
Search
1
解决visual studio code (vscode)安装时没有选择安装路径问题
322 阅读
2
如何在 Clash for Windows 上配置服务
218 阅读
3
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
150 阅读
4
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
149 阅读
5
uniapp打包app提示通讯录权限问题,如何取消通讯录权限
114 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,284
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
847
篇与
的结果
2024-10-20
真没必要再对 axios 进行过度的封装
前几天在某网站上看到一篇文章,说是用 ts 对 axios 进行了下封装,从点赞量、评论量和访问量上来看,有很多人都看过这篇文章了。我之前也看过 axios 的源码,也基于 axios 进行过扩展和二次封装。对 axios 的内部原理和使用方式不可谓不熟悉。虽然很多人在评论里说,收益匪浅啊,写的真棒啊等等,但我通读完整篇文章,得到的结论是:完全没必要。 1. 完全没必要 # 有的开发者喜欢基于 axios 再在外层封装一层,但这种方式实现的成本太高。无论是实现跟 axios 一样的功能,还是外层进行简化,然后再按照 axios 的方式传给 axios,都增加了很多开发的成本。如:const myAxios = async (config) => { /** * 中间各种封装,然后最后再使用axios发起请求1 * */ try { const { status, data } = await axios(config); if (status >= 200 && status { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [result, setResult] = useState(null); useEffect(() => { setLoading(true); axios(config) .then(setResult) .catch(setError) .finally(() => { setLoading(false); }); }, []); return { loading, error, result }; }; 更具体的如何在 React 封装一个请求的 hook,可以参考该链接:使用 react 的 hook 实现一个 useRequest。有的封装,是为了减少项目整体的改造成本,和其他人学习新用法的成本。比如之前我也基于 axios,在外层封装过一个请求库。当时为了跟之前的请求方式保持一致,就在外层额外封了一层。后来就出现当需要扩展功能时,特别麻烦,还不如从一开始设计时,就仅仅扩展他的适配器,或者几个简单的配置就行。在封装的时候,首先我们要明白 axios 可以完成什么工作,他实现这些功能都有什么意义,为什么可以传入这些字段,又为什么要返回了那么多字段(我明明只需要接口返回的 data)?想明白这些问题,就知道我们要保留什么,如何进行扩展和封装了。 3. 总结 # 我在很久之前写过一篇文章:前端工程师如何通过造轮子提高自己,但似乎这篇文章的观点与之前的冲突了。其实,并不冲突。造轮子是为了通过模仿成熟的作品来提高自己,但真的在实际应用时,我们就要考虑得更多。自己实现出来的东西,大部分都比不上社区里经过千锤百炼验证过的。而且在使用的过程中,还要考虑减少其他人的学习成本。比如你就不想用 Vue,觉得 Vue 这个框架优点大,然后选择了一个叫mini-vue的框架来开发项目。就社区完善程度来说,这个 mini 版肯定是比不上官方 Vue 的,后来者还得重新学习 mini 版的语法,当遇到问题时,都不知道去问谁,毕竟这个问题,只有 mini 版里才会有,其他人用的少,解答的人也少。
2024年10月20日
13 阅读
0 评论
0 点赞
2024-10-20
leetcode367 判断该数是否是完全平方数
题目地址 367. 有效的完全平方数。题目要求不能用库函数来直接开平方,本意是希望用二分法来解决该问题。 1. 完全平方数的解决方案 # 两种方式: 直接检索:从 1 开始匹配,挨个儿匹配 num,直到能匹配上(返回 true),或超过 num(返回 false)。时间复杂度为 O(n); 二分查找:取中间数来匹配 num,匹配上就直接返回,否则根据大小来决定取左边或者右边; 无论使用哪种方式,都应该注意类型范围和精度这两个问题。题目中限制了 num 的范围在[1, 2^31-1],若我们选择了 int 类型,并且用乘方结果来跟 num 进行匹配时,无论是直接检索还是二分查找,都会极大概率出现超过类型范围的问题。这里应该选择long long类型。同时,取中间值时,不要直接(left+right)/2,这也会超出 int 范围的,应该使用 left + 偏移量的方法:mid = left + (right - left) / 2; 我们换个角度,为避免数字超过类型范围,用 num 来除以这个数 mid,再判断商是否等于 mid。但在 C/C++中,会舍弃小数,导致判断失败,如 10000 和 10001 两个数字:int result0, result1, mid = 100; result0 = 10000 / 100; result1 = 10001 / 100; result0 == mid; // 正确,expect true, receive true result1 == mid; // 错误, expect false, receive true 这里最好再用取余判断下是否可以整除,最终的代码:class Solution { public: bool isPerfectSquare(int num){ int left, right, mid; int square; left = 1; right = num; while (left mid) { left = mid + 1; } else { right = mid - 1; } } // 没找到 return false; } }; 2. 平方根 # 这里还有个上面平方数的姊妹篇:69. x 的平方根,即求 x 的平方根的整数位置。跟上面的思路一样,要考虑取中间数的方式和用于相除来代替相乘,避免超出整型数字范围。最终实现的代码如下:class Solution { public: int mySqrt(int x){ if (x 1); result = x / mid; // 已自动取整 if (result == mid) { return mid; } if (result > mid) { // result大,说明mid做为除数偏小,应当向右移动 left = mid + 1; } else { right = mid - 1; } } return right; } }; 关键点在于 x / mid在强制类型的语言中会自动取整,因此若mid == x / mid时,就说明 mid 是 x 的平方根的整数部分。如数字 4 的平方根正好是 2 ;而 5/2==2,因此 2 就是 5 的平方根的整数部分;数字 6 则是在循环里找不到对应的数字的,会在最后返回 right 指向的值。
2024年10月20日
8 阅读
0 评论
0 点赞
2024-10-20
leetcode2244 如何使用最少的轮数完成任务
题目链接:2244. 完成所有任务需要的最少轮数。题目的关键点有: 只能完成相同难度级别的任务; 每轮只能完成 2 个或 3 个任务; 使用最少的轮数; 因此我们的思路应当是:统计每个难度级别任务的数量,然后优先 3 个一轮来完成任务,最后剩下的再通过 2 个任务的组合来完成。 只有难度级别的任务的数量为 1 时,无法完成,数量>=1 的,都可以通过 2 和 3 的组合来完成。 优先完成 3 个相同级别的任务,那么最后任务剩余的数量可能是: 0 个:恰好是 3 的倍数; 1 个:还剩下 1 个,但这种情况最后一轮就无法完成了,因此再从前面拿出一个 3,通过 2+2 的方式完成; 2 个:通过完成 2 个相同难度级别的方式完成; 最终实现的 C++代码:class Solution { public: int minimumRounds(vector &tasks){ map location; // 存储每个级别任务的数量 int leftTaskNum; // 相同级别任务3个一轮全部完成,剩余的任务数量 for (int i = 0, size = tasks.size(); i < size; i++) { auto it = location.find(tasks[i]); if (it == location.end()) { location.insert(pair(tasks[i], 1)); } else { it->second += 1; } } map::iterator it = location.begin(); int num = 0; while (it != location.end()) { int item = it->second; if (item
2024年10月20日
7 阅读
0 评论
0 点赞
2024-10-20
http-proxy-middleware 的注意事项
这篇文章不是 http-proxy-middleware 的使用教程,关于如何使用,还请参考官方教程。主要是说下自己之前使用时的注意事项。 1. 无法继续流转路由 # 如我们在使用 express 等框架时,会声明多个路由的,有的路由是用来处理业务逻辑,有的是收集相关信息,有的是用作拦截器等。import { createProxyMiddleware } from 'http-proxy-middleware'; import express from 'express'; const app = express(); app.use('*', createProxyMiddleware()); app.use('*', () => { console.log('after createProxyMiddleware'); // 无法输出 }); const port = Number(process.env.PORT) || 3001; const ip = process.env.IP || '127.0.0.1'; app.listen(port, ip, () => { const msg = `[server]: Server is running at http://${ip}:${port}`; console.log(msg); }); 若上面 ↑ 的代码,在对*进行拦截请求后,后续的路由服务将不再执行。因此对该路由的一些处理,应当放在 http-proxy-middleware 的前面。我们从源码 ↓ 中就可以看到,createProxyMiddleware()返回的是一个 middleware 方法,即对路由的处理方法:// https://github.com/chimurai/http-proxy-middleware/blob/35ac1dbd29ff0953f978373dd6add081819087de/src/index.ts#L4 export function createProxyMiddleware(options: Options): RequestHandler { const { middleware } = new HttpProxyMiddleware(options); return middleware; } 而在 middlware 的方法 ↓ 中可以看到,若代理过程是正常的,则不会再执行next()的逻辑。// https://github.com/chimurai/http-proxy-middleware/blob/35ac1dbd29ff0953f978373dd6add081819087de/src/http-proxy-middleware.ts#L40 export class HttpProxyMiddleware { public middleware: RequestHandler = async (req, res, next?) => { if (this.shouldProxy(this.proxyOptions.pathFilter, req)) { try { const activeProxyOptions = await this.prepareProxyRequest(req); debug(`proxy request to target: %O`, activeProxyOptions.target); this.proxy.web(req, res, activeProxyOptions); } catch (err) { next && next(err); } } else { next && next(); } } } 因此,后续的路由不会再接收请求。 2. onProxyRes 无法处理 content-length 为 0 的数据 # 我们可以在 onProxyRes 中对获取到的数据进行二次处理,然后再返回。如官方给到的样例intercept-and-manipulate-responses,将 Hello 替换为 GoodBye:const { createProxyMiddleware, responseInterceptor } = require('http-proxy-middleware'); const proxy = createProxyMiddleware({ /** * IMPORTANT: avoid res.end being called automatically **/ selfHandleResponse: true, // res.end() will be called internally by responseInterceptor() /** * Intercept response and replace 'Hello' with 'Goodbye' **/ on: { proxyRes: responseInterceptor(async (responseBuffer, proxyRes, req, res) => { const response = responseBuffer.toString('utf8'); // convert buffer to string return response.replace('Hello', 'Goodbye'); // manipulate response and return the result }), }, }); 但是,若代理转发地址返回的数据,response header 中,不存在content-length字段,或者该字段的值为 0。则 onProxyRes 中的 responseBuffer 为空,无法处理处理数据。如一些 CDN 或者 COS 上的数据,他为了快速响应,或者使用了 chunked 编码(transfer-encoding: chunked),在返回数据时,通常没有 content-length 这个字段。
2024年10月20日
13 阅读
0 评论
0 点赞
2024-10-20
各种 2 到 62 任意进制之间的转换
我们在平时生活中通常会遇到 10 进制转其他进制,或其他进制转为 10 进制,那我们就可以通过 10 进制进行中转,实现各种任意进制的转换。大部分编程语言都仅限在 2-36 进制内的转换,这里我们拓展到 62 进制,即小写字母z的下一位用大写字母A表示,直到大写字母Z。我们先来熟悉下 10 进制之间的转换,然后进行统一。 1. 其他进制转为 10 进制 # 其他进制转为 10 进制时,将当前的基数乘以当前的位权,然后全部相加即可,如一个 8 进制的数字 123:123 = 1 * 8^2 + 2 * 8^1 + 3 * 8^0; = ((1 * 8) + 2) * 8 + 3; 通过这个简单的推导,我们在用代码实现时,可以从左到右,先用当前数字乘以进制,然后再参与下一位的运算,直到结束。进制超过 10 时,会出现字母,这里我们需要把字母转为数字再进行计算。字母转为数字:/** * 将letter转为纯数字 * @param {char} letter * @return {int} */ int transformCharToNum(char letter){ if (letter >= '0' && letter = 'a' && letter = 'A' && letter a num /= to; } reverse(result.begin(), result.end()); return result; } 使用方式:covert10ToOther(13, 2); // 将10进制里的13转为2进制,结果为1101 covert10ToOther(7, 2); // 111 covert10ToOther(13, 5); // 23 3. 任意进制转任意进制 # 任意进制之间的转换,我们只需要把上面的两种方式组合在一起就行了。这里中间需要 10 进制中转一下。我们将进制转换扩展到了 62 进制,里面可能会包含英文字符,因此我们的输入和输出都定义成了 string 类型。若您需要的是纯数字格式的,还请自行转换。class Solution { public: /** * 将num从base进制转为to指定的进制 * @param {string} num 要转换的数字字符串 * @param {int} base num的进制 * @param {int} to 转换后的进制 * @return {string} */ string covert(string num, int base, int to){ // 当base和to相等 或 base和to超出转换范围,则原样返回 if (base == to || !this->checkRadixLegal(base) || !this->checkRadixLegal(to)) { return num; } // 先转成10进制 int p = 0, number10 = 0; while (p < num.length()) { number10 *= base; number10 += this->transformCharToNum(num[p]); p++; } // 若要转换的正好是进制,则直接返回 if (to == 10) { return to_string(number10); } int cur; string result; while (number10) { cur = number10 % to; result.push_back(this->transformNumToChar(cur)); number10 /= to; } reverse(result.begin(), result.end()); return result; } private: bool checkRadixLegal(int radix){ return radix >= 2 && radix = '0' && letter = 'a' && letter = 'A' && letter
2024年10月20日
16 阅读
0 评论
0 点赞
1
...
93
94
95
...
170