xingbofeng.github.io
xingbofeng.github.io copied to clipboard
counterxing的博客
2018年度总结
儿时总想快快长大,也曾想象过20岁生日的样子,结果20岁生日是个周天,那天在加班,晃晃荡荡终于恍到了20岁,就以这篇文章大概记载一下自己20岁这一年吧。 这次不想像上次年度总结那样,列一些无聊的list,书单,我更喜欢想到哪就写到哪这种方式。 > “我是新来的实习生,今年不到20岁。” “姐都一把老骨头了,以后别跟我提你年龄!” ——在有道的自我介绍。 > "博峰,考神这个活动页明天就要上线,要不今晚咱们就住在公司吧。我上半夜给测试,下半夜你把bug修好,明天咱们直接上线" ——第一次不是在网吧度过的通宵 > “姐,我想尝试一下新的挑战,这个项目用Vue可以吗?” ——第一次用新技术栈扛下项目 > “本来想取名叫Encounter,但是因为公司取名加上姓氏拼音必须11字符以内,所以counter就这么诞生了,谁叫自己的姓占的字符太多呢?” ——新鹅第一件事就是取一个好听的名字,我觉得counter其实还OK 看看去年要求,不知算是完成了几个: * 加强锻炼:算是半个吧,至少还是瘦了20斤的 * 学习Python,学算是学了,但是没用,忘也忘得差不多了 * 实习顺利转正:很幸运地留在了鹅厂,现在坐在鹅厂的位置上用着鹅厂的网写这篇流水账 * 把学分修完:算是修完了吧,最后一科重修考试考了93 * BAT offer:运气超好拿到鹅厂offer,可是我好菜啊,拿到offer只是开始 至于书单,肯定没看完,但是一半多是看过了吧,今年就不立去年那么多的flag了,至少把这些书刷完吧: * 《UNIX网络编程》...
## cornerstone enable API 在每次`loadImage`之前都需要进行`enable`,至于`enable`到底做了哪些事情,对外来说确实是不可见的。 * 创建`canvas`节点 * 初始化`enabledElement`对象 * 全局`cornerstone`存储`enabledElement`列表 * 初始化事件,轮询是否需要更新图片 ### 创建canvas节点 创建canvas节点前,首先判断这个element是否存在,如果存在,继续看是否`option`是否有`webgl`的`option`。之后创建节点,并置为`enabled element`的子节点。 ```javascript if (element === undefined) { throw new Error('enable: parameter element cannot be...
用了这么久的[cornerstone](https://github.com/cornerstonejs/cornerstone),恰好这又是我的毕设题目,而且个人觉得`cornerstone`的代码写的算是比较优秀,所以打算从阅读源码的过程中多学习一点东西。 ## cornerstone加载医学影像显示的全过程 在cornerstone,一个`enabled element`就是一个`HTML DOM`节点(例如,一个`div`),cornerstone会在其中展示一些交互式的医学影像。为了展示这些影像,开发者需要做以下事情: 1. 将cornerstone库通过`script`标签引入你的`web`页面中。 2. 将cornerstone的图片加载器(image loaders)引入你的`web`页面中,图片加载器会使用`WADO`、`WADO-RS`或`custom`协议加载医学影像图片并提供给`web`页面使用。 3. 把`enabled element`这个`DOM`节点加入到你的页面中去,在这个`DOM`节点内会展示医学影像。 4. 使用`CSS`为这个`element`固定好宽度和高度。(切记一定要固定宽高) 5. 调用enable(),准备在节点内展示影像。 6. 调用loadImage()加载影像。 7. 调用displayImage()展示影像。 ## 看imageLoader imageLoader一共有下列几个方法: * 私有方法`loadImageFromImageLoader(imageId, options)` * 公开方法`loadImage(imageId,...
学了这么久的设计模式,最近一直在看`Node.js`的设计模式,一直纳闷为何会有模式这一类东西的存在,那么模式究竟是什么东西?后面在看了《面向模式的软件架构》之后才慢慢知道有了一些系统的概念。 ## 模式是什么? 面对特定问题时,专家很少去寻找与既有解决方案截然不同的新方案,而通常会想起一个以前解决过的类似问题,并将其解决方案的精髓用于解决这个新问题。 从特定问题—解决方案中提炼出通用的因素便可得到模式:这些问题—解决方案通常是一系列熟悉的问题和解决方案,其中每对问题—解决方案都呈现出相同的模式。 ### Model-View-Controller模式 `MVC`模式大量用在现代软件开发流程中,为何会有`MVC`模式的存在,来看这一个例子:开发带人机界面的软件。 用户界面需求容易变化。例如,添加应用程序功能时,必须修改菜单以便能够访问新功能,还可能需要针对特定客户调整用户界面。系统可能需要移植到另一个平台,而该平台采用的“外观”标准完全不同。即便是升级到新的窗口系统版本,也可能需要修改代码。总之,如果系统的使用寿命很长,可能经常需要修改用户界面。设计灵活的系统时,让用户界面与功能核心紧密地交织在一起将付出高昂的代价,且容易出错。这样做的后果是,可能需要开发和维护多个大不相同的软件系统——每种用户界面实现一个,且修改将涉及众多不同的模块。总之,开发这种交互式软件系统时,必须考虑如下两个方面: * 应该能够轻松地修改用户界面,在运行阶段就能完成; * 调整或移植用户界面时,不应影响到应用程序功能核心的代码。 为解决这种问题,应将交互式应用程序划分成三部分:处理、输出和输入。 * 模型(`model`)组件封装核心数据和功能,独立于输出表示方式和输入行为。 * 视图(`view`)组件向用户显示信息。视图从模型那里获取它显示的信息,一个模型可以 有多个视图。 * 每个视图都有相关联的控制器(`controller`)组件。控制器接受输入,通常是表示鼠标移动、鼠标按钮激活或键盘输入的事件。事件被转换为服务请求,而服务请求要么被发送给模型,要么被发送给视图。用户只通过控制器与系统交互。 通过将模型与视图和控制器组件分开,让同一个模型可以有多个视图。如果用户通过一个视图的控制器修改了模型,这种变更应在依赖相关数据的其他所有视图中反映出来。为此,每当模型的数据发生变化时,它都会通知所有视图,而视图将从模型那里检索新数据,并更新显示的信息。这种解决方案确保了修改应用程序的一个子系统时不会严重影响其他子系统。例如,可将非图形用户界面改成图形用户界面而无需修改模型子系统,还可支持新的输入设备而不影响信息的显示和功能核心。所有软件版本都可依赖同一个模型子系统,该子系统独立于“外观”。  ### 用Model-View-Controller模式实现一个鉴权服务 我们从下图所示的结构开始分析:  上图显示了`Model-View-Controller模式`的典型示例;它描述了一个简单的鉴权服务的结构。`AuthController`接受来自客户端的输入,从请求中提取登录信息,并执行一些初步验证。之后`AuthService`检查客户端提供的凭证是否与存储在数据库中的信息匹配;最后使用`db`模块执行一些特定的查询来完成的,作为与数据库通信的一种手段。这三个组件连接在一起的方式将决定应用程序的可重用性,可测试性和可维护性。 在这里:模型(`Model`)指的就是`db`模块,控制器(`Controller`)指的就是`AuthController`和`AuthService`,而视图则是前端的用户界面,也就是`HTML`文档。 将这些组件连接在一起的最自然的方法是通过`AuthService`请求`db`模块,然后从`AuthController`请求`AuthService`。...
本文配有demo,[猛戳此处访问demo](https://github.com/xingbofeng/cpu-bound-demo) 大量占用`CPU`计算资源的任务称为`CPU-bound`的任务。 它的主要特点是`CPU`利用率较高,而不是`I/O`操作繁重。 让我们立即举一个例子上看看这些类型的任务在`Node.js`中的具体行为。 ## 暴力求解子集求和问题 问题:类似于[Leetcode-40. Combination Sum II](https://leetcode.com/problems/combination-sum/description/) > Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where...
原文链接:[Catching without Awaiting](https://hueniverse.com/catching-without-awaiting-b2cb7df45790) 当执行一项需要等待一段时间才能返回的任务时,如果使用`async/await`,就显得比较麻烦了。如果`async`方法还没有得到返回值,我们就捕获不到其中的异常。 在我的上一篇文章[Learn to Throw Again](https://hueniverse.com/learning-to-throw-again-79b498504d28)中写到,当使用`async/await`时,如何同时捕获到回调函数和`throw`抛出的错误。在这篇文章中,我们将讨论如何在“后台”中执行异步操作并捕获异常(这里使用双引号,因为在单线程平台上没有真正的后台操作) 从回调函数的模式开始,思考下列代码: ```javascript function email(user, message, callback) { if (!user) { // 抛出异常 throw new Error('Invlid user'); } if (!user.address) { // 回调函数,可能抛出异常...
一年三城
上周向腾讯递交了辞呈,算是给这一年画上了一个句号。 先说结果吧,结果应该是留用十拿九稳,但具体的结果需要等到九月初才能知晓。现在全面校招还未开始,手里除腾讯这个不完全稳的offer外一个offer,有道叫回去可以参加转正答辩,实在遭不住奔波,遂放弃。 这一年经历的第一次太多了,比如说第一次用`React`、第一次用`Vue`、第一次用`Koa`什么的😆 ,开个玩笑。四张机票、N张电影票,给自己添置了很多新装备,许多新衣服,新的背包,一台`Mac笔记本`、一个`iPhone`手机等等。走过一些城市,东北长春、哈尔滨,北京、天津,到深圳。认识了许多有趣的人和业界比较厉害的人。也都在他们身上学到很多东西。在创宇学到的平静对待需求变化,学到自己怎么更好地去解决问题。在有道学到的精细做事,不给他人添麻烦。在腾讯学会怎么更好地去融入团队,怎么更好地在规范流程下把事情做好。学会了吃亏,学会与人更和善。在北京搜狐快站认识了一群有趣的人,在合租生活中也认识了一群优秀的人。并且自己知道的之前一直没醒悟到的道理。 有一天晚上,跟一个朋友聊天。之前一直隐隐约约又没悟出来的道理,大概是为什么这个堂子里,会有这样的二八法则。我不认为高考毕业进入一个学校的人都比我优秀,但为何三年后大家各有不同。 在大学这个堂子里面,要想变得优秀,一定要跟优秀的人一起抱团,远离寝室,远离那些颓废的人。我发现受优秀的人的影响,我心态变了很多,也比以前踏实了一些。我在北京的室友,他们信安竞赛能拿到这么高的奖项,首先跟他们的努力分不开,他们大晚上在实验室忙完后回到家还在视频开会讨论比赛的事。其次,这个比赛不是他们的第一个比赛,他们从一开始就建立了深厚的革命友谊。而在这个堂子里面,大部分人都是都不是很耐得住寂寞和很有自制力,几个优秀的人在一起,他们相互促进,取长补短。会变得越来越优秀。虽然现在快毕业了,虽然我起点比他们低了一些,但是我会努力工作赶上他们的脚步的。以上,对以前自己走的弯路的一些反思。 我想以这个主题,如果现在问我一个问题:在这一年,成都到北京再到深圳的生活中,每个地方自己印象最深刻的事是什么? ## 在创宇 我一直觉得这一年是我过得太幸运了,从一开始就是。好似多米诺骨牌效应,如果最开始创宇没有录用我,也就没有后来的能去到北京,有幸去搜狐认识那一群有意思的朋友,有幸去有道积累一大波的实习经历,也正是因为有道的经历,最终让自己坐在深圳腾讯的办公大楼内,拿着还算稳的offer,写着现在的事儿。 通过创宇的面试,说实话是我的幸运,当时的技术真的不怎么样,也感谢当时姚总把我招进去了,不然没有自己后来的路。另外一点的收获是是自己初入职场,太过毛躁,对于设计图变更和需求变更和精细程度的要求不适应。造成了一些沟通的困难和麻烦。从这里也是学到很多平静与淡定处理事情。 ## 在有道 说实话,有道的实习机会是我“骗来”的。记得面试的时候,我说我会`React`,其实只是在`render`里面写过`HTML`而已,`redux`也不太会用,不过还是看过很多面经,恰好跟面试官聊得来,就得到了这份来之不易的实习机会。 自己在有道的技术提升是飞跃的,虽然工作中很多部分是在跟样式打交道(实习生嘛,干不了太核心的活,我也比较淡然)。但利用业余时间学了很多东西。`Vue`、`Express`、`Koa`等等等等。 如果说在有道自己最深刻的事,真的数都数不清。我知道自己实习的目的是好好练技术,把之前没学好的东西补起来,所以迫不及待地想参与组内的项目。因为技术原因吧,当时在做题库测试,没能很好地参与进项目,那次心中是特别焦心,觉得失去了实习的意义,甚至有点想离开。第二次是做活动页熬了一个通宵, 那次是真的感受到了自己的一个价值。 团队氛围蛮好的,以致于最后离开的时候都还很舍不得,来深圳拼了一把,还算值得。 ## 在腾讯 在腾讯我觉得最幸运的两件事吧,一件事是莫名其妙地通过了面试,第二件事是莫名其妙地拿到了实习留用。 可知道一年前我还是个连`jQuery`的`API`都背不熟的小菜鸟呢。 在腾讯的日子相对来说就平淡了许多,用着自己用过的技术做着自己还算喜欢的事情。这一切都得感谢之前在有道的培养,在有道踩过的那些坑。现今的心情其实就是心中有着很多感悟,特别是关于这两个月的。 如何做事,这个问题真的蛮抽象,算是抛砖引玉。首先要与人和善,这个是前提,做事情,一定要做善事,不做恶事。其次是积极主动,也就是行动力。我总结这一年我走过的路,之所以运气那么好,是在于自己做事雷厉风行,想到一件事,就立马去做,想找实习,立马投递简历,想离开搜狐,立马提离职。工作中,做完的事想好怎么把它做得更好,没做完的事尽量保质做完。生活中,想离开一个地方去另外一个地方,立马订票,绝不拖沓。 另外,善于思考,多去思考,做完一个项目去想想我应该怎么样去更好地优化代码风格,站在维护者的角度去读你的代码可读性。组内的`code review`就是一个很好的机会,其次,一定要按照组内的规范来,无规矩不成方圆,去读他们的代码,思考他们为何要这么写,这么写的原因是什么,每一次下来都可以得到更好的一个提升。最后,在一个阶段之后,做好总结,这个是很必要的,这样每个阶段都能有一些收获。做到一定程度之后,回归教材,回归基础知识,很多地方也能恍然大悟。这便是思考的重要性。 谨以此文送给这一年的自己,希望未来好运可以一直伴随着自己呢!
# 什么是柯里化? ## 官方的说法 在计算机科学中,[柯里化](https://zh.wikipedia.org/wiki/%E6%9F%AF%E9%87%8C%E5%8C%96)(英语:`Currying`),又译为`卡瑞化`或`加里化`,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。这个技术由`克里斯托弗·斯特雷奇`以逻辑学家`哈斯凯尔·加里`命名的,尽管它是`Moses Schönfinkel`和`戈特洛布·弗雷格发明的`。 在直觉上,柯里化声称**如果你固定某些参数,你将得到接受余下参数的一个函数**。 在理论计算机科学中,柯里化提供了在简单的理论模型中,比如:只接受一个单一参数的`lambda`演算中,研究带有多个参数的函数的方式。 函数柯里化的对偶是`Uncurrying`,一种使用匿名单参数函数来实现多参数函数的方法。 ## 方便的理解 > Currying概念其实很简单,只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。 如果我们需要实现一个求三个数之和的函数: ```javascript function add(x, y, z) { return x + y + z; } console.log(add(1, 2, 3));...
本文灵感源于《深入浅入Node.js》第三章 ## 先看microtasks 这是一道常见的无聊的面试题: ```javascript setTimeout(() => { console.log(1); }, 0); new Promise((resolve, reject) => { console.log(2); for (let i = 0; i < 10000; i++) { i === 9999...
最近在看新出的`Nicholas`的大作《深入理解ES6》时,发现有一些语法还是平时基本没用到,但是也是写在了最新的`ECMAScript`标准中的语法,所以想用这篇文章记录一下这些可能被我们忽略的ES6语法。 ## 反射(Reflect)和代理(Proxy) `ECMAScript6`添加了一些内建对象,赋予开发者更多访问`JavaScript`引擎的能力。代理(`Proxy`)是一种可以拦截并改变底层`JavaScript`引擎操作的包装器,在新语言中通过它暴露内部运作的对象,从而让开发者可以创建内建的对象。 代理可以拦截`JavaScript`引擎内部目标的底层对象操作,这些底层操作被拦截后会触发相应特定操作的**陷阱函数**。 反射API以`Reflect`对象的形式出现,对象中方法的默认特性与相同的底层操作一致,而代理可以覆写这些操作,每个代理陷阱对应一个命名和参数都相同的`Reflect`方法。 | 代理陷阱 | 覆写的特性 | 默认特性 | | ------| ------ | ------ | | get | 读取一个属性值 | Reflect.get() | | set | 写入一个属性...