首页
Search
1
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
69 阅读
2
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
52 阅读
3
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
42 阅读
4
如何在 Clash for Windows 上配置服务
40 阅读
5
如何在 IOS Shadowrocket 上配置服务
40 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,061
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
1061
篇与
的结果
2024-10-20
如何写一篇垃圾的技术文章
很多人都从“如何写一篇好的技术文章”的角度,分析了很多。我这里从另一个角度,来说一下如何写出一篇垃圾的技术文章。 1. 抄袭或者复制粘贴 # 完全把别人的文章粘贴过来,或者只复制粘贴其中的某一部分。并且对复制过来的内容,完全不理解,只是觉得好而已。当用户有疑问想要咨询的时候,完全不理他,毕竟把文章抄袭过来,指向要多赚一些流量而已。比如可以这样: 2. 言之无物 # 说了一大堆理论,虽然看着内容很多,但最终可以不知所云,让读者最后啥也不知道,完全不知道讲了什么。例如今年 2020 年的浙江高考作为《生活在树上》中写到的: 现代社会以海德格尔的一句‘一切实践传统都已经瓦解完了’为嚆矢。滥觞于家庭与社会传统的期望正失去它们的借鉴意义。但面对看似无垠的未来天空,我想循卡尔维诺“树上的男爵”的生活好过过早地振翮。 用在树上的生活方式体现个体的超越性,保持婞直却又不拘泥于所谓“遗世独立”的单向度形象。这便是卡尔维诺为我们提供的理想期望范式。生活在树上——始终热爱大地——升上天空。 文章中虽然引用了多个名人的名言,但不乏各种生僻的词汇,令人晦涩难懂。读起来觉得高大上,但又不知道在说什么。技术文章也是同理,可以用上各种的新鲜词汇,包括但不限于: 人工智能; 互联网思维; 孵化器; 平台战略; 颠覆式创新; 多重容灾、负载均衡; 私域流量; 让读者读起来,可以莫名地感叹:“哇”,“太牛逼了”,“真厉害”……。 3. 结构混乱 # 大部分好的文章都是“总-分-总”的结构。开头点题,说明当前文章的本意;中间部分剖析问题并提出解决方案;最后部分进行总结并升华主题。那么一篇垃圾的技术文章,必须不能按照这个结构来写。 我们可以只说遇到了什么问题,或者解决后有多好,但不说解决方案,让用户抓耳挠腮,自以为找到了答案; 只说解决方案,但不说解决了什么问题,比如可以直接贴一段代码,不用解释每行都是干嘛的,让读者自己理解去,理解不了,就是他的能力差; 前后文逻辑不通,东扯一句,西拉一段,想到什么写什么; 满屏的错别字,有的因为错别字完全变成了其他的意思; 全是文字,也没有流程图、结构图之类的; 通过上面的几个准则来写作,一篇满满的垃圾技术文章,已经要呼之欲出了。 4. 没有验证过的代码或方案 # 代码是在写文章时,临时写的,不用验证,肯定没问题。有些技术方案,都是我脑子一热想起来的,也没有线上的验证,但肯定没问题。例如这段代码,看看错在哪里了:// 这段代码是错误的,请勿直接使用 function getQueryString(name) { const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'); const result = window.location.search.substr(1).match(reg); return decodeURIComponent(result[2]); } 注意,上面的代码不要直接使用哈,若要使用,可以访问 javascript 获取 URL 链接和 js 链接中的参数。再或者提出了多级缓存的方案,只说大方向,不具体探讨多级缓存是如何搭建的、缓存穿透是如何解决的,命中率如何等。让读者在实际应用的时候,还是无所适从,漏洞百出。 5. 想说明所有的关键点 # 别人都会把一些关键点搞成一个系列,每篇文章只讲一个关键点。但我偏要逆势而行,要在一篇文章里,把所有的关键点都说了,每个关键点都解释的不深。或者为了解释某个观点,又引入了其他一堆的观点,但引入的观点也不细讲。到这里,一篇垃圾的技术文章就已经写好了。
2024年10月20日
3 阅读
0 评论
0 点赞
2024-10-20
CSS:水平居中并限定最大的宽度
在最近工作中,遇到一个这样的问题: 1. 背景 # 水平三栏或者两栏的布局,其中一栏内的内容是变动的; 当内容过少时,整体需要居中展示; 当内容过多时,需要根据最大的宽度进行省略; 2. 实现的思路 # 整体的容器要添加属性:.container { display: flex; justify-content: center; } 2.1 使用 flex:1 来实现 # 之前的代码里,把变动的那一栏设置为flex: 1或者flex: auto,但这样存在的问题是,这块会把容器剩余的所有空间都占满,而不会根据内容自动调整; 2.2 设置 flex: none 来实现 # 这个存在的问题是,当内容过多时,不会盖住过多的内容 2.3 不设置属性 # 中间内容不固定的,则不设置任何 flex 属性,如果已经设置了不够,记得重新覆盖掉:.clamp { flex: initial; } 注意,这里使用的是initial,而不是 none。同时还要注意,其他栏的宽度不要被挤压。我们左侧这一栏本来是放着一个图片,有设置宽度,但还是因为中间这一栏的内容过多,导致图片被压缩变形。所以,图片这里添加了一个min-width的属性。
2024年10月20日
3 阅读
0 评论
0 点赞
2024-10-20
如何实现 axios 的自定义适配器 adapter
Axios 是一个非常优秀的基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。并且提供了很多便捷的功能,例如: 支持 Promise API 拦截请求和响应 转换请求数据和响应数据 取消请求 自动转换 JSON 数据 客户端支持防御 XSRF 但如果我们想基于 axios 扩展一些自己的数据请求方式(例如 mock 数据,某些 APP 内专属的数据请求方式等),并能够使用上 axios 提供的便捷功能,该怎么自定义一个适配器 adapter; 1. 适配器要实现的功能 # 我们在基于 axios 实现额外的数据模块时,应当与 axios 的模式进行对齐。因此在返回的数据格式上,实现的功能上尽量保持一致。 1.1 promise 和工具 # 所有的适配均应当实现为 Promise 方式。而且,有些功能的实现,axios 将其下放到了适配器中自己进行实现,例如 url 的拼接:即 baseURL 和 url 的拼接,若存在 baseURL 且 url 为相对路径,则进行拼接,否则直接使用 url; 参数的拼接:若是 get 请求,需要自行将 object 类型拼接为 url 参数的格式并与 url 拼接完成; 这是自己需要实现的两个基本的工具方法。 1.2 响应的格式 # 这里我们要注意到请求接口正常和异常的格式。接口正常时:const result = { status: 200, // 接口的http 状态 statusText: 'ok', config: 'config', // 传入的config配置,原样返回即可,方便在响应拦截器和响应结果中使用 data: {}, // 真实的接口返回结果 }; 接口异常时,我们可以看下 axios 源码中对错误信息的处理createError,enhanceError(createError 中调用了 enhanceError),首先会创建一个 error 实例,然后给这个 error 实例添加一个属性:module.exports = function enhanceError(error, config, code, request, response) { error.config = config; if (code) { error.code = code; } error.request = request; error.response = response; error.isAxiosError = true; error.toJSON = function toJSON() { return { // Standard message: this.message, name: this.name, // Microsoft description: this.description, number: this.number, // Mozilla fileName: this.fileName, lineNumber: this.lineNumber, columnNumber: this.columnNumber, stack: this.stack, // Axios config: this.config, code: this.code, }; }; return error; }; 可以看到,除了正常的错误信息外,还加入了很多别的属性,例如 request, response, config 等。这里我们在自己实现适配器时,最好也要这样统一编写,方便更上层的业务层统一处理,避免为单独的适配器进行特殊处理。关于 1.1 和 1.2 中的内容,若不进行打包编译,则需要自己实现。若还要通过 webpack 等打包工具编译一下的,可以直接引用 axios 中的方法,不用自己实现了,参考官方基于 axios 实现的mock-axios。例如:import axios from 'axios'; import buildURL from 'axios/lib/helpers/buildURL'; import isURLSameOrigin from 'axios/lib/helpers/isURLSameOrigin'; import btoa from 'axios/lib/helpers/btoa'; import cookies from 'axios/lib/helpers/cookies'; import settle from 'axios/lib/core/settle'; import createError from 'axios/lib/core/createError'; 然后直接使用就行了,不用再进行二次开发。 1.3 超时设置 # 我们不能无限地等待第三方服务的响应,如果第三方服务无响应或者响应时间过长,应当适时的终止掉。在 axios 中,前端使用了XMLHttpRequest,在 node 端使用了http,来实现接口的请求,两者都有超时的设定,可以设置 timeout 字段来设置超时的时间,自动取消当前的请求。像有的发起的请求,自己并没有超时的设定,例如 jsonp,是用创建一个 script 标签来发起的请求,这个请求必须等到服务器有响应才会终止(成功或者失败)。这时,就需要我们自己用一个setTimeout来模拟了,但这样,即使返回给业务层说“超时了,已取消当前请求”,但实际上请求还在,只不过若超过规定时间,只是不再执行对应的成功操作而已。 1.4 主动取消请求 # 我们也会有很多并没有到超时时间,就需要主动取消当前请求的场景,例如在请求返回之前就切换了路由;上次请求还没响应前,又需要发出新的请求等。都需要主动地取消当前请求。axios 中已经提供了取消请求的功能,我们只需要按照规则接入即可。我们来看下 XMLHttpRequest 请求器中是怎么取消请求的,在写自定义请求器时也可以照理使用。在lib/adapters/xhr.js#L158中:// 若config中已经配置了cancelToken if (config.cancelToken) { // Handle cancellation // 若在外城执行了取消请求的方法,则这里将当前的请求取消掉 config.cancelToken.promise.then(function onCanceled(cancel) { if (!request) { return; } // xhr中使用abort方法取消当前请求 request.abort(); reject(cancel); // Clean up request request = null; }); } 我们在写自己的适配器时,也可以将这段拷贝过去,将内部取消的操作更换为自己的即可。关于 cancel 操作执行的原理,这里暂不展开,有兴趣的可以参考这篇文章:axios cancelToken 原理解析。到这里,若把上面的功能都实现了,就已经完成了一个标准的适配器了。 2. 编写自定义适配器 # 每个人需要的适配器肯定也不一样,复杂度也不一样,例如有的想接入小程序的请求,我自己想接入客户端里提供的数据请求方式等。我们这里只是通过实现一个简单的jsonp适配器来讲解下实现方式。我们以 es6 的模块方式来进行开发。所有的实现均在代码中进行了讲解。// 这里的config是axios里所有的配置 const jsonpAdapter = (config) => { return new Promise((resolve, reject) => { // 是否已取消当前操作 // 因jsonp没有主动取消请求的方式 // 这里使用 isAbort 来标识 let isAbort = false; // 定时器标识符 let timer = null; // 执行方法的名字, const callbackName = `jsonp${Date.now()}_${Math.random() .toString() .slice(2)}`; // 这里假设已经实现了baseURL和url的拼接方法 const fullPath = buildFullPath(config.baseURL, config.url); // 这里假设已经实现了url和参数的拼接方法 // 不太一样的地方在于,jsonp需要额外插入一个自己的回调方法 const url = buildURL( fullPath, { ...config.params, ...{ [config.jsonpCallback || 'callback']: callbackName }, }, config.paramsSerializer ); // 创建一个script标签 let script = document.createElement('script'); // 成功执行操作后 function remove() { if (script) { script.onload = script.onerror = null; // 移除script标签 if (script.parentNode) { script.parentNode.removeChild(script); } // 取消定时器 if (timer) { clearTimeout(timer); } script = null; } } // 成功请求后 window[callbackName] = (data) => { // 若已需要请求,则不再执行 if (isAbort) { return; } // 返回的格式 const response = { status: 200, statusText: 'ok', config, request: script, data: data, }; remove(); // 实际上这里上一个settle操作,会额外判断是否是合理的status状态 // 若我们在config.validateStatus中设置404是合理的,也会进入到resolve状态 // 但我们这里就不实现这个了 // settle(resolve, reject, response); resolve(response); }; // 请求失败 script.onerror = function (error) { remove(); reject(createError('Network Error', config, 404)); }; // 若设置了超时时间 if (config.timeout) { timer = setTimeout(function () { remove(); // 取消当前操作 isAbort = true; reject( createError( 'timeout of ' + config.timeout + 'ms exceeded', config, 405 ) ); }, config.timeout); } // 若定义了取消操作 if (config.cancelToken) { config.cancelToken.promise.then(function () { if (!script) { return; } remove(); isAbort = true; reject(createError('Cancel Error', config, 404)); }); } script.src = url; const target = document.getElementsByTagName('script')[0] || document.head; target.parentNode && target.parentNode.insertBefore(script, target); }); }; export default jsonpAdapter; 3. 将适配器添加到 axios 中 # axios 的 config 提供了 adapter 字段让我们插入自己的适配器。使用自定义适配器又有两种情况: 完全只使用自定义的适配器; 在某种情况下使用自定义适配器,其他情况时还是使用 axios 自己的适配器。 第 1 种情况还好,只需要 return 自己适配器返回的结果结果即可;而第 2 种情况中,则有个小坑需要踩一下,我们这里也只讲解下第 2 种情况。我要把刚才实现的 jsonp 适配器添加到 axios 中,并且只在参数有format=jsonp时才调用该适配器,其他还是用的 axios 提供的适配器。import Axios from 'axios'; import jsonpAdapter from './jsonpAdater'; const request = Axios.create({ adapter: (config) => { if (config?.params?.format === 'jsonp') { return jsonpAdapter(config); } // 这里需要将config.adapter设置为空 // 否则会造成无限循环 return defaultAxios({ ...config, ...{ adapter: undefined } }); }, }); 使用方式,点击查看 demo【axios 自定义的 jsonp 适配器】:使用自定义的适配器 jsonp 发起请求。// 使用自定义的适配器jsonp发起请求 var options = { params: { format: 'jsonp', }, }; request( 'https://api.prize.qq.com/v1/newsapp/answer/share/oneQ?qID=506336', options ) .then(function (response) { console.log('jsonp response', response); }) .catch(function (error) { console.error('jsonp error', error); }); 使用 axios 默认的适配器发起请求。// 使用axios默认的适配器发起请求 request('https://api.prize.qq.com/v1/newsapp/answer/share/oneQ?qID=506336') .then(function (response) { console.log('axios response', response); }) .catch(function (error) { console.error('axios error', error); }); 4. 总结 # 这里,我们就已经实现了一个自定义适配器了,在满足一定条件时可以触发这个适配器。通过这个思路,我们也可以实现一个自定义的 mock 方法,例如当参数中包含format=mock时则调用 mock 接口,否则就正常请求。
2024年10月20日
3 阅读
0 评论
0 点赞
2024-10-20
useState 与 requestAnimationFrame 实现的useAnimationFrame
我们在之前的文章 如何构建自己的 react hooks 中实现过useInterval的自定义 hook。我们有个进度条,需要从进度 0 逐渐增加到固定的进度时,使用 useInterval 就可以实现。 1. 复习 useInterval # 我们再看看之前的useInterval是怎么实现的。const useInterval = (callback, delay) => { const saveCallback = useRef(); useEffect(() => { // 每次渲染后,保存新的回调到我们的 ref 里 saveCallback.current = callback; }); useEffect(() => { function tick() { saveCallback.current(); } // delay变为null的的时候,会先清除掉之前的定时器 // 然后也不会起新的定时器,整个useInterval结束 if (delay !== null) { let id = setInterval(tick, delay); return () => clearInterval(id); } }, [delay]); }; 使用 useInterval 来实现下进度的变化:const progress = 76; // 当前的实际进度 const [step, setStep] = useState(0); // 进度的过程 // useInterval怎么实现的可以查看上面的链接 useInterval( () => { setStep(step + 1); }, step < progress ? 20 : null ); // 当为数字时则按照这个数字切换,若为null则停止定时器 但使用 useInterval 的话,颗粒度不够细,可能就会存在丢帧的情况。这里我们就要考虑到使用requestAnimationFrame来实现进度的一个变化。 2. 实现 useAnimationFrame # 我们可以仿照 useInterval 的写法来写一个 useAnimationFrame,但要注意的是,setInterval 是启动之后就不用再管了,他会自动按照间隔来执行下一个任务,但 requestAnimationFrame 类似于 setTimeout,每次都要在当前任务里去启动下一个任务,这样就会产生一个新的 requestId(取消时使用),因此这个新的 requestId 也要用一个 ref 来保存:const useAnimationFrame = (callback, running) => { const savedCallback = useRef(callback); // 传进来的callback const requestId = useRef(0); // 当前正在执行的requestId useEffect(() => { savedCallback.current = callback; }); useEffect(() => { function tick() { savedCallback.current(); if (running) { // 当running为true时,才启动下一个,并拿到最新的requestId requestId.current = window.requestAnimationFrame(tick); } } if (running) { const animationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame; const cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame; requestId.current = animationFrame(tick); return () => cancelAnimationFrame(requestId.current); } }, [running]); }; 我们实现了 useAnimationFrame 后,就可以使用这个来实现进度的变化:const progress = 76; // 当前的实际进度 const [step, setStep] = useState(0); // 进度的过程 useAnimationFrame(() => { setStep(step + 1); }, step < progress); // 这里为true和false useAnimationFrame的 hook 相比 useInterval,数据变化会更加流畅,点击查看 demo:useAnimationFrame 的使用。 3. 基于 useAnimationFrame 实现更多的功能 # 我们在useAnimationFrame中只是实现了基本的数据变化功能,但实际应用中,还需要更多的功能,例如: 监听每一步的变化,监听动画结束事件; 手动启动、暂停进度变化; 数据按照动画效果进行变化; 控制进度的快慢 step; 因此,可以基于 useAnimationFrame 封装一个更加复杂的组件和useProgress的自定义 hook; 3.1 实现 Progress 组件 # 我们先定义几个 Progress 组件的属性:interface ProgressProps { startNum?: number; // 起始进度 endNum?: number; // 结束的进度 step?: number; // 每一步跳跃的进度 running?: boolean; // 进度是否进行 onStart?: () => void; // 监听开始事件 onStep?: (step: number) => void; // 监听进度变化事件 onEnd?: () => void; // 监听进度结束的事件 } 我们当前组件其实只需要通过一个running字段来控制进度是否前进。这时,我们就可以编写组件了。const Progress = ({ startNum = 0, endNum = 100, step = 1, running = false, onStart = () => {}, // 开始的回调 onStep = () => {}, // 每一步的回调 onEnd = () => {}, // 结束时的回调 }: ProgressProps) => { const [progress, setProgress] = useState < number > startNum; onStart(); useAnimationFrame(() => { const nextProgress = Math.min(progress + step, endNum); if (nextProgress ({ // 这里是暴露给父组件的方法 // 开始 start() { setRunning(true); }, // 暂停 pause() { setRunning(false); }, // 切换状态 toggle() { setRunning(!running); }, // 重新开始 restart() { setProgress(startNum); setRunning(true); }, })); 点击查看 Progress 组件的使用:Progress 组件的使用。 3.2 实现 useProgress 的 hook # 若希望更加简洁一些,只想获取当前的进度,可以基于 useAnimationFrame 自定义一个useProgress的 hook:const useProgress = ({ startNum = 0, endNum = 100, step = 1, running = true, }) => { const [progress, setProgress] = useState(startNum); useAnimationFrame(() => { const nextProgress = Math.min(progress + step, endNum); setProgress(nextProgress); }, running && progress < endNum); return progress; }; 这里的 useProgress 只是返回了当前的进度,使用起来也非常地方便:const progress = useProgress({}); return ( progress: {progress} ); 4. 总结 # 这里我们总结了下 useState 和 requestAnimationFrame 封装的 useAnimationFrame 的 hook,然后通过这个 hook 可以很方便地控制页面中 state 的变化。本来想在 useProgress 中可以根据三次贝塞尔曲线来进行一个进度的曲线变化,但研究了一下发现,三次贝塞尔曲线的坐标(x, y)都是通过变量 t 得到的,这里需要推导出一个 y=f(x)的公式,根据 x 得到 y 的变化,比较麻烦,这里就不展开讲了。
2024年10月20日
3 阅读
0 评论
0 点赞
2024-10-20
前端工程师如何通过造轮子提高自己
我们常说“不要重复造轮子”,如果别人已经有实现好的、经过验证的好轮子,就拿来用就好了,如果有什么疑问的时候,还能很方便地在网上找到答案。是的,我们确实不要轻易地造轮子,尤其是在一些大型场景下,一个不经意的小错误,可能也会引起大问题。除了自己,大家都希望不要重复造轮子,产品只要按时并稳定上线即可,总监们只要最后的数据即可。而我们自己,却要思考下,用的整个轮子是怎么造出来的,如果我来实现这样的功能的话,应该怎么实现。别人的轮子对自己来说就是一个黑盒,我们只是负责使用即可。但如果我们想要深入细节的话,最好还是自己实现一遍更好,即使没有人家实现的好。自己重复造轮子有以下的几个好处。 1. 提高自己的能力 # 通过造一个自己的轮子后(不一定正式环境要使用),就更能明白这些技术方面的细节。当然,我们也不要陷入一个误区,啥功能都要自己开发一遍。我们在时间比较充裕的情况下,探究技术上的细节,而不是事无巨细,皆以身亲之,在项目工期要求的前提下,自己不可能很完整地实现。简单的功能,我们可以自己先实现下,复杂的功能建议先用成熟的组件,事后再探究内部的原理。假如我们想要实现一个前端的数据请求模块 request,目前行业的标杆是axios。针对我们自己的业务场景,可以试着自己先实现一下,至少能满足当前业务的需求。当我们完成这个模块,并能正常实现请求后,再与 axios 进行对比,看人家是怎么实现的: axios 为什么这么实现,同样的功能我是怎么实现的? axios 比自己多了哪些功能,有什么好处,例如我们只是得到了接口返回的数据,而 axios 则返回了{config,data, request}等字段; 扩展性如何,当想要在 request 模块中添加功能时,是否要大刀阔斧重构,还是做成了插槽; 当我们对比完这些功能的残缺后,再完善自己的轮子。完善后再去阅读 axios 的源码,就会发现 axios 的代码结构、功能实现等,非常的赞。自己造的轮子未必有很多人使用,但本身探究的过程就已经非常地值得。这些过程就是财富,就是自己的能力。 2. 提高知名度 # 基于自己业务造的轮子,并不断地完善和改进,就会有越来越多的人来了解和使用你的轮子,也提高了你的知名度。我们技术人员应当要树立起自己的品牌,给自己加上一个与众不同的标签,每当说起这个标签时,自然而然地就能想到你。作为开发者,如何树立个人品牌?,这是几年前转载的一篇文章,现在读来,依然觉得还是很有价值。例如当我们说起 CSS 大神、图片女神张含韵,必然就能想到张鑫旭;说起前端蚊子大神、造轮子小能手,就必然说的是我。 3. 造轮子的步骤 # 如何造轮子?我们的轮子必然是要服务我们的业务的,因此我们可以从业务的特点出发。如果我实现了这个功能,下一个项目就能直接使用。 3.1 针对自己的业务实现简单的功能 # 我们的页面会在腾讯新闻客户端和微信、QQ 中访问比较多,在现在前后端分离的场景下,都是通过接口请求完成交互。在微信、QQ 或者浏览器中采用XMLHttpRequest或者fetch可以完成接口请求,而在腾讯新闻客户端中,有一种特别的请求方式。那么我就要封装一下这个请求模块了,可以让业务层无需关心当前请求从哪个终端发起,所有的判断均在模块内部完成,对外提供一个完整和统一的配置。这里我会先判断当前环境是否是新闻客户端,如果是,则使用新闻客户端里的请求方式,否则若存在 fetch 方法,则使用 fetch,最后使用 XMLHttpRequest。这个数据请求模块,已经满足我当前业务的需要了。 3.2 提炼为小模块 # 后来随着写的项目越来越多,越需要通过源码拷贝的方式在多个项目之间传递,并且随着自己能力的提高,模块越来越完善,bug 越来越少。但之前的项目想要更新这块的功能时,不知道如何更新,从哪个项目把更完善的代码拷贝回来呢?这时,我就就把这个功能封装成一个 npm 包发布出来,这样每个项目只使用这个包就可以了。之前的项目里需要升级这块时,只需要更新到对应的版本号即可。而且其他人也可以使用,而不是直接源码拷贝的方式来进行传递! 3.3 学习第三方成熟轮子的结构和实现方案 # 在项目向着更大的场景展开时,例如我们使用到了 node 同构直出渲染,就要考虑到在 node 服务端发起的接口请求。这时,我就想到,除了在新闻客户端中的特殊请求外,在微信、QQ、浏览器和 node 服务端的请求,均可以使用 axios 来实现。然后基于 axios,再搭配上新闻客户端的特殊请求,就更完美了。不仅解决了跨多终端请求的麻烦,还能使用到 axios 提供的能力。在看 axios 的源码中,也学习到了他的代码结构搭配和配置的能力,同时 axios 还提供了请求拦截器和响应拦截器的能力,方便我们能在请求前和请求后做一些处理。并且还能够避免 XSRF 的攻击漏洞。 3.4 发布自己的组件 # 在学习 axios 这款优秀的数据请求组件后,便可以对自己的组件进行更好地改造,拥有更好的性能和扩展性,并发布出自己的组件,能够支撑更多、更大的业务。 4. 总结 # 但行造轮子,莫问前程。其实在重复造轮子的过程中,我们更加关心的是造轮子的过程,从中收获了哪些。我是蚊子,一个造轮子小能手。
2024年10月20日
3 阅读
0 评论
0 点赞
1
...
40
41
42
...
213