首页
Search
1
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
69 阅读
2
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
51 阅读
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
能用js重写的都会被typescript重写
没用过typescript可能会下面的两个疑问: javascript越来越完善,还有没有必要学习typescript? typescript学习的成本如何呢? 1. typescript的生态 # 针对这两个疑问我们来稍微地解答下:typescript是javascript的超集,所有es2016, es2017, es2018等等,包括未来的标准就会被包含在typescript中:尤其在多人合作的项目中,typescript能强制开发者的标准,对其他的开发者能天然的做到文档提示的功能,例如这段代码:/** * 判断当前商品的状态 * qcoin/object/redpack/flow类型的商品里,1表示待领取,2表示已领取; * code,url等类型的商品,会直接进行发送,1就表示已领取,没有状态2 * 统一后:state: 0:未成功, 1:待领取, 2:已领取, 3:已过期, 4:已下架 * * @param state 当前商品的状态 * @param type qcoin(QB), object(实物), code(兑换码), url(纯链接), redpack(现金红包), flow(流量型) */ const getOrderState = (state: number, type: string): number => { if (state === 1 && (type === 'code' || type === 'url')) { return 2; } return state; }; 在调用getOrderState方法时,能直接提示该方法有几个参数,每个参数的类型是什么,返回的数据是什么类型的,如果错误地调用了该方法,则在编写阶段就会提示出来!同时通过Google的搜索量上来看,大概有1850万的搜索结果,typescript的生态是越来越好。而且,typescript对angular和react有着优良的支持,在使用react编写代码的过程中,同时尤雨溪也在用typescript对Vue3.0进行重写。之前尤雨溪也在知乎上说压flow压错了宝,typescript真香https://www.zhihu.com/question/310485097/answer/591869966。 2. typescript的学习成本 # typescript的学习非常的低,针对一些平常的操作,随手就可以写上相应的类型。function sum(a: number, b:number): number { return a + b; } sum(23, 56); 针对比较复杂的数据类型,可以通过interface来实现:interface GoodsItem { cost: number; // 现价 cover: string; // 图片 customer_service: string; // 规则 desc: string; // 描述 discount_score: number; // 积分价格 icon_url: string; // icon prize_enname: string; prize_zhname: string; rule: string[] | string; // 规则名 score_cost: number; // 积分兑换的价格 sending_count_today: number; // 今日发放的上限 sending_count_total: number; // 总量 short_name: string; // 短名称 sort: number; // 权重 state: number; // 状态 type: string; // 类型 validity: string; // 有效期 } let goods: GoodsItem; // 使用GoodsItem来定义goods变量 当然,对一些更加复杂的,比如泛型等则需要特意地学习下。这里可以看下知乎上总结的typescript骚操作。 3. 总结 # 最开始写页面时,使用的是Vue,那时候就是纯按照教程上的方式来编写的,例如data, computed, watch等方法。在后来的项目中,使用vue-property-decorator来进行实现,虽然对于默认的对象书写方式有类型推导支持,但里面的实现绕了很多弯。问题的本质其实很简单:因为当初 API 的设计根本就没有考虑类型系统,Vue2.x对typescript支持的非常不好,我们也期待Vue3.0出现的变更。最近改用react写新的项目时,typescript发挥它很大的优势,类型提醒、数据提示(如dom对象下的方法)等,支持地都特别棒.自从接触了typescript,总想着把之前所有用javascript实现的代码再用typescript重构一下。但是,历史代码能不动还是别动了,在以后新的项目中好好使用typescript即可!
2024年10月20日
5 阅读
0 评论
0 点赞
2024-10-20
前端中的事件循环eventloop机制
我们知道 js 是单线程执行的,那么异步的代码 js 是怎么处理的呢?例如下面的代码是如何进行输出的:console.log(1); setTimeout(function() { console.log(2); }, 0); new Promise(function(resolve) { console.log(3); resolve(Date.now()); }).then(function() { console.log(4); }); console.log(5); setTimeout(function() { new Promise(function(resolve) { console.log(6); resolve(Date.now()); }).then(function() { console.log(7); }); }, 0); 在不运行的情况可以先猜测下最终的输出,然后展开我们要说的内容。 1. 宏任务与微任务 # 依据我们多年编写 ajax 的经验:js 应该是按照语句先后顺序执行,在出现异步时,则发起异步请求后,接着往下执行,待异步结果返回后再接着执行。但他内部是怎样管理这些执行任务的呢?在 js 中,任务分为宏任务(macrotask)和微任务(microtask),这两个任务分别维护一个队列,均采用先进先出的策略进行执行!同步执行的任务都在宏任务上执行。宏任务主要有:script(整体代码)、setTimeout、setInterval、I/O、UI 交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)。微任务主要有:Promise.then、 MutationObserver、 process.nextTick(Node.js 环境)。具体的操作步骤如下: 从宏任务的头部取出一个任务执行; 执行过程中若遇到微任务则将其添加到微任务的队列中; 宏任务执行完毕后,微任务的队列中是否存在任务,若存在,则挨个儿出去执行,直到执行完毕; GUI 渲染; 回到步骤 1,直到宏任务执行完毕; 这 4 步构成了一个事件的循环检测机制,即我们所称的eventloop。回到我们上面说的代码:console.log(1); setTimeout(function() { console.log(2); }, 0); new Promise(function(resolve) { console.log(3); resolve(Date.now()); }).then(function() { console.log(4); }); console.log(5); setTimeout(function() { new Promise(function(resolve) { console.log(6); resolve(Date.now()); }).then(function() { console.log(7); }); }, 0); 执行步骤如下: 执行 log(1),输出 1; 遇到 setTimeout,将回调的代码 log(2)添加到宏任务中等待执行; 执行 console.log(3),将 then 中的 log(4)添加到微任务中; 执行 log(5),输出 5; 遇到 setTimeout,将回调的代码 log(6, 7)添加到宏任务中; 宏任务的一个任务执行完毕,查看微任务队列中是否存在任务,存在一个微任务 log(4)(在步骤 3 中添加的),执行输出 4; 取出下一个宏任务 log(2)执行,输出 2; 宏任务的一个任务执行完毕,查看微任务队列中是否存在任务,不存在; 取出下一个宏任务执行,执行 log(6),将 then 中的 log(7)添加到微任务中; 宏任务执行完毕,存在一个微任务 log(7)(在步骤 9 中添加的),执行输出 7; 因此,最终的输出顺序为:1, 3, 5, 4, 2, 6, 7;我们在Promise.then实现一个稍微耗时的操作,这个步骤看起来会更加地明显:console.log(1); var start = Date.now(); setTimeout(function() { console.log(2); }, 0); setTimeout(function() { console.log(4, Date.now() - start); }, 400); Promise.resolve().then(function() { var sum = function(a, b) { return Number(a) + Number(b); } var res = []; for(var i=0; i
2024年10月20日
3 阅读
0 评论
0 点赞
2024-10-20
记一次项目中分享图片的过程
我们的项目主要是在新闻客户端中进行使用,会经常调用客户端提供的jsapi完成各种操作。前些天我们上线了一个非常重要的功能:分享图片。通常分享图片到微信的步骤比较繁琐:先长按保存图片,然后打开微信,点击朋友圈分享,然后在相册里选择刚才保存的图片,最终分享成功。而现在新上线的分享图片功能,能够直接从新闻客户端分享到微信朋友圈,省略了中间保存图片和选择图片的过程。在新闻客户端里的页面分享到微信朋友圈,从前端角度可以拆分为以下几个步骤: 跨域的图片地址转为base64; 图片对应的链接转为二维码的base64地址; 使用html2canvas将DOM结构转为base64图片地址; 使用websocket将base64地址传到后台,然后返回CDN地址; 调用客户端提供分享图片的jsapi,将4中的CDN地址传进去,呼起分享; 将跨域的图片转为base64是因为在canvas通过toDataURL()方法转换时,跨域的图片是无法转换的,必须将其转为本地图片才可以。对于第4步中将base64转为线上的CDN地址,则是因为客户端jsapi的要求,无法直接传递base64地址。在使用html2canvas把DOM结构转为图片的过程中,踩过2个坑:1. 无法使用圆角,无法使用透明的背景,最开始打算分享的图片是圆角的,结果生成的图片是圆角的,同时背景里某个地方是镂空的,结果生成的图片里,变成了白的背景色;2. 边框border无法使用虚线,我在某个地方使用border: 2px dashed #888,结果生成的图片里变成了实线。我们上面分享图片是一个依赖过程,当前步骤须依赖上一个步骤的完成情况,必须上一个步骤成功了,才能执行当前步骤。中间哪个步骤出错了,都无法成功分享图片,那么这里做的兜底操作是分享文章型链接。this.$emit('upProgress', 0); // 进度为0,表示分享图片的流程开始 try { let p1 = img2base64byApi(); let p2 = img2base64byApi(); let p3 = qrcode(); await Promise.all([p1, p2, p3]); this.$emit('upProgress', 1); // 进度为1,将跨域的图片全部转为base64 let base64Url = await convertHtml2Canvas('.shareimg'); this.$emit('upProgress', 2); // 进度2,将dom结构转为base64图片 let imgurl = await upImgByWs(base64Url); this.$emit('upProgress', 3); // 进度3,base64图片地址转为CDN地址成功 await showBigImageShareMenu(imgurl); this.$emit('upProgress', 4, imgurl); // 进度4,呼起图片的分享成功 } catch(e) { // 上面任意一个步骤出错,均认为分享图片失败 // 转为分享文章 console.error(e); this.$emit('upProgress', -1); // 进度-1,分享图片失败 } 在实现img2base64byApi, qrcode, convertHtml2Canvas这些方法的过程中,注意对缓存的使用,因为相同的图片地址最终转换后的base64图片也是一样的。因此,将某个图片转换base64成功后,将原图片和转换后的base64图片地址缓存起来,待下次再次调用时,直接返回即可,避免了不必要地重新转换。const qrcode = (str: string): Promise => { if (cache.getCache(str)) { return Promise.resolve(cache.getCache(str)); } return new Promise((resolve, reject) => { QRCode.toDataURL(str) .then((code: string) => { cache.setCache(str, code); resolve(code); }) .catch(reject); }); }; 总结一下,在实现这个功能中,也是耗费了不少地时间,遇到了一些问题。主要是Promise的合理使用,同时注重缓存的重要性。
2024年10月20日
5 阅读
0 评论
0 点赞
2024-10-20
高考毕业10年后的我活成了...
1. 高考 # 2019年的高考马上就要来了,想想自己的高考已经是10年前的事情了。10年,真是眨眼就过去了,尤记得10年前在考场上奋笔疾书的样子,记得10年前的高中生活,每天都是早起晚归。那时候还在想着如何能提高高考分数,我能考上什么样子的大学。尤记得我在教室的墙上书写的志愿是武汉大学。自己那时候的模拟成绩并不突出,志愿显然是有点高了。可是这张粘贴在墙上的志愿,却激励了我整个高三的生活,让我想着能每天都朝着目标一点点靠近。无论复习地好,还是复习地差,高考终究还是要来的。还记得6月7日高考的第一天中午,上午已经考完了一科语文,中午吃完饭溜达到门口时,发现父亲从老家赶来。我那时也没有手机,并不知道父亲从老家赶过来。他们也知道自己帮不上忙,但还是想过来看看,如果我没有走到校门口,父亲也只能在校门外看着里面的校园。他说让我别动,给我买两袋橘子;可是我阻止了他,因为附近没有月台。高考后,意味着我们高中三年的生活就要结束了,我们都将要踏上新的征程。 2. 我的大学 # 步入大学的生活,可以说既悠闲又充实,可以有更多的时间来充实自己。能利用上这些空闲时间的人最后也会在毕业时,与其他人拉开差距。有人说,大学生毕业就意味着失业。那显然说的是不愿意提升自己的大学生,荒废了4年,还怪学校没有提供好的资源。我们学校作为山西高校里最大的图书馆,又有谁充分地利用起来了。我在大学毕业前就找到了实习的工作,毕业后也相应的在那里入职。作为我步入社会的呃第一家公司,真的教会了我很多很多,虽然后面因为各种各样的辞职了,但我依然感激它。加油! 3. 前端 # 目前在鹅厂做前端开发工程师也将有4年的时间了。这几年前端工作中,也是能体会到前端技术的革新。作为专业的前端开发,应当注重自己的专业能力和业务水平。在这里,我希望引用下我博客里的一段话:我眼中的优秀的技术人员: 对技术充满热情 编程是生活的一部分 会在你的耳边谈论技术相关的话题,如果你有兴趣的话 主动学习新技术 对自己不能认同的技术,感到不适应,无法全身心投入 聪明,对很多话题都感兴趣 在大学之前就开始接触编程了 有隐藏的冰山,自己完成的大项目 对许多不相关的技术有了解 4. 现在 # 作为最早的一批90后,一晃,高考竟然已经过去10年了,自己的孩子也有了。自己也马上将要步入而立之年。我的博客是从2012年开始写的,这一晃也断断续续写了7年。从最开始的自娱自乐,作为自己的笔记,到现在分享自己的经验。把工作和学习中遇到的问题,进行更深的挖掘,一方面是让自己更加了解里面的原理,同时也希望能帮助到有类似问题的同学。回顾自己之前写的文章,当时也因为自己认知的局限性,会写一些观点错误或者论据不足的文章。有时候在回顾时,也会有新的想法产生。高考10年后的我: 文章依然写的不好,像流水账; 前端储备依然不足,还远远达不到要求; 有了自己的孩子,他现在刚刚会走路,也会简单的跳舞; 我们高中的同学,我们,已经毕业10年了。 但,我依然在奋斗;依然在坚持写作;依然奋斗在答辩的路上。我知道,还有你们在! 岁月走过不小心踩伤了受了伤的心尖,痛、始终不曾明灭的萦绕着苍白憔悴的思念。是否前世我淡薄寡怜了你一世的情愫?岁月走过光阴的沧海,遗落了一路的伤碎桑田心愿,在年岁风烛蚕食里是否还有痕迹?
2024年10月20日
2 阅读
0 评论
0 点赞
2024-10-20
Can’t perform a React state update on an unmounted component
最近项目中有一个这样的需求,从别的项目要转到我项目中的某个页面,不过回退时要可以回退到项目的首页。实现这样的跳转的话,应当是首先要跳转到项目的首页,然后再从首页跳转到对应的页面。我最开始的实现是这样的:componentDidMount() { const jumpUrlList = ['own']; const jumpUrl = getQueryString('jumpto'); const targetJump = window.sessionStorage && window.sessionStorage.getItem('targetJump'); // 防止无限跳转,使用sessionStorage存储一个标记,整个周期内只跳转一次 if (jumpUrlList.indexOf(jumpUrl) > -1 && !targetJump) { window.location.href = '#/' + jumpUrl; window.sessionStorage.setItem('targetJump', '1'); } } 但运行时,会提示这个错误: Warning: Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method. 意思是:无法对没有实例的组件进行响应状态更新。您可以在 componentWillUnmount 方法中取消所有的订阅和异步任务。因为我在首页中有异步请求,请求返回回来后,使用setState更新视图。但我已经跳转到别的路由了,导致 setState 更新时,当前组件已被销毁了,无法更新。解决方法: 若您的异步请求可以取消的话,在 componentWillUnmount 中取消请求; 在render()方法中进行判断,若可以跳转,则直接不渲染; render() { const jumpUrlList = ['own']; const jumpUrl = getQueryString('jumpto'); const targetJump = window.sessionStorage && window.sessionStorage.getItem('targetJump'); if (jumpUrlList.indexOf(jumpUrl) > -1 && !targetJump) { window.location.href = '#/' + jumpUrl; window.sessionStorage.setItem('targetJump', '1'); return null; } return ( ); } 使用高阶组件重新封装 componentWillUnmount 和 setState; function inject_unount(target) { // 改装componentWillUnmount,销毁的时候记录一下 let next = target.prototype.componentWillUnmount; target.prototype.componentWillUnmount = function() { if (next) next.call(this, ...arguments); this.unmount = true; }; // 对setState的改装,setState查看目前是否已经销毁 let setState = target.prototype.setState; target.prototype.setState = function() { if (this.unmount) return; setState.call(this, ...arguments); }; } @inject_unount class BaseComponent extends Component {} //以后我们写组件时直接继承BaseComponent
2024年10月20日
4 阅读
0 评论
0 点赞
1
...
33
34
35
...
213