122017.9

在最开始接触一个依赖的时候,把关于^~等符号的版本管理弄清楚的时候,觉得这个好伟大,然而当躺进坑里,才发现,这东西是害人的。对一个第三方package的依赖,默认安装会在版本前面加^,当第二次执行npm install的时候,如果发现npm服务器上存在比该版本大的小版本号,就会使用新的版本的package。然而,然而!当新的版本对当前环境不兼容时,特别是那些被依赖的很深的package发生这种情况,对于开发者而言,简直就是噩梦。昨天做build的时候一切还正常,连代码都没改动,今天再做build的时候,却怎么也通不过了。造成这个问题的原因,是因为所有的package的版本都向后兼容,虽然你的项目代码没有变,但是你的第三方依赖代码变了,如果新的第三方代码不兼容你当前的node版本,那么就是一个惨字。解决的唯一办法,是通过升级npm版本,升级之后,package都是扁平化的,然后再在package.json文件中,把那个不兼容的package固定在较低的版本中。

我个人的观点是,一个项目,之所以能够正常运行,是因为在开发时选择了适合的版本,而且是经过测试的。倘若在第二次运行时,代码不同,那么怎么保证之前的测试是有效的呢?因此,npm install不应该自作主张的从服务器选择更新的版本,而是在本地安装允许的最新版本。比如jquery,安装本地所有package中允许的最新版本,而不是比本地允许的版本还要新的版本。

09:21:05 已有0条回复
062017.9

在一个软件中,使用多个语言进行混合编程,不同的服务用最好的语言去执行得到结果,例如node和Python混合,php和c++。那么怎么实现呢?其实语言之间的混合编程原理很简单,以一个语言为入口程序,另一个语言为后台程序,在入口程序中如何调用后台程序的执行结果呢?那就要用到入口程序的execute能力,通过调用命令行工具,执行后台程序,并且有非常便捷的方式得到后台程序的执行结果。

这里有一篇如何实现node和python混合的文章,简单的说,就是利用node child_process能力,通过exec执行一个命令行命令,这个命令行命令调用python程序执行,并且把执行结果输出在child_process的stdout中,node在对stdout的输出结果进行解析即可。

说到这里,你就发现多语言混合编程也并不困难了。

11:14:07 已有0条回复

量化分析数据资源

https://github.com/thuquant/awesome-quant

发现一个超级棒的量化分析资源收集页面

302017.8

HHuploadify 升级,一个风骚的版本

HHuploadify是一个纯粹的图片上传组件,说纯粹是因为只考虑把它用来上传图片。当然,上传文件也是没问题的,但是文件上传的UI应该和图片上传的UI有较大的区别,而且文件上传也不存在preview的问题。

为什么要升级?

HHuploadify最初的版本是我在Huploadify这个jquery插件的基础上开发的,UI改了,上传的时候支持的功能多了。在发布后的几年里,不断有人问我xxx可不可以,我的大部分回答,都是要自己写代码实现。这几天因为公司产品release之后相对有点闲了,就打算重写一遍HHuploadify。

大概花了两天的时间,重构过程还算顺利,最开始想支持IE8,但最后因为iframe提交时报dined错,就只能放弃了。现在插件能支持到IE9(IE9也有一点坑,但是大部分情况下还过得去)。而且,最重要一点,它不依赖jquery了。它是一个独立的组件,而且我发布到npm了。我这两年都在用webpack babel等构建工具,所以依赖感比较强,写ES6也很随意,所以源码都是ES6写的,ES6归ES6,但是有些api要考虑IE9,所以还是没敢太大胆用,比如还是在用for...in。但是,我已经习惯了直接import, export这样的语法,所以,当我想重新用HHuploadify的时候,发现不好用,它只是一个jquery插件。这就催生我重写一遍它。对于那些还在用或者准备要用的同学们,我可能要很遗憾的说,你想要实现的都可以实现,但是你要写的代码可能更多了。之所以这样,是因为我之前封装了几个函数,现在把它们去掉了,整个组件的核心都在这里,只需要通过class extends或者钩子函数就可以非常好的进行扩展。

看看DEMO

所以,它现在变得很风骚,不信你可以先看看效果:

最初级的配置,选择图片(多选)后点击上传按钮进行上传

添加一个auto的配置,选择图片(多选)之后自动上传图片

默认情况下,点击选择图片按钮后,打开的选择器可以一次性选择多张图片。如果是用户头像,那么只能选一张图片,只需要配置一个single选项即可。配置之后,这个实例只能上传一张图片。开始上传之后,选择按钮就会消失。

上传成功之后,用server端返回的url字段中的url作为新的预览图片。在一些需要裁剪的情况下可能会用到,只需要把showPreview设置为2即可。

通过showUploadProcess的配置,采用不同的上传进度展示效果。

假如你想默认就有几张图片,也是可以的,使用reset方法即可。

对HHuplodify进行扩展也超级简单,上图演示的就是利用jquery.dragsort插件扩展HHuploadify,对上传之后的图片列表可以拖拽的效果。

利用single选项,进行简单扩展之后,就可以实现一组固定的上传。

通过钩子函数,对上传的最大张数进行控制。上面图片演示中,最多只能上传4张图片。

这些场景应该很多都会覆盖你的上传的情况吧。当然,你有特殊的需求,没关系,只需要extends class或者在钩子函数中写逻辑即可。可配性强的同事,接口还是完全暴露可复写的。

安装和使用

你可以直接像以前一样在浏览器中直接引用,但是你也可以像module一样import到你的项目中,我已经发布了npm包,所以你可以这样干:

npm i -S hhuploadify
import 'hhuploadify/dist/HHuploadify.css' // 在webpack中可以直接使用css了import HHuploadify from 'hhuploadify'

let uploader = new HHuploadify({

  container: '#upload',

  url: 'http://localhost/upload',})

然后,在那个#upload的容器中就会有一个上传的UI效果出来。uploader就是这个实例了,它包含了所有的methods,你可以用它干你想干的事。当然,你也可以在配置中传入钩子函数来干你想干的事。

看下怎么扩展它:

import HHuploadify from 'hhuploadify'

export default class extends HHuploadify {

  myMethod() { // 新方法

  

  console.log(this.files)

  }

  reset(files) { // 复写的方法

  

  super.reset(files)

  

  console.log(files)

  }}

这样你就扩展出一个新方法,复写了一个原型链方法。是不是非常简单。

下载和仓库

如果你看了网上的一些资料,按照它们提供的方法来使用,可以下载1.0版本,如果你想给我提bug或者contribute的话,在github仓库上玩弄吧。

18:02:24 已有1条回复
  1. 这个好可以
    #867 这个好可以 2019-12-09 23:17 回复
212017.8

机器学习入门资源不完全汇总

102017.8

karma配置中有一个frameworks选项,这个选项的作用是在执行单元测试代码 *.spec.js 文件之前,载入对应的框架,而这些框架都要以插件的形式加入到plugins选项中。比如:

frameworks: ['mocha', 'sinon-chai'],
plugins: [
  'karma-mocha',
  'karma-sinon-chai',
],

一旦这样做了,那么在你的测试代码中,就不用自己再引入对应的框架,这也是为什么你可以直接在spec.js文件中直接使用describe和it函数。上面这个配置example,你不必再在测试代码中引入mocha、chai和sinon来使用对应的方法,它们的所有api已经被载入到karma的运行环境中了。chai的expect/assert等函数可以直接使用,sinon被作为一个全局变量,它的方法也可以直接使用。

10:15:02 已有0条回复
012017.8

babel-loader和webpack UglifyJS一起使用时console的问题

一起使用babel-loader和webpack UglifyJS时,babel会优先处理一遍代码,编译后的代码才进入webpack进行打包和优化操作。在使用扩展运算符...时,不同的情况会进行不同的处理。当在函数参数中使用时,会编译为arguments,而在调用参数时会编译为apply,如下:

function debug(...args) {
  console.log(...args)
}

会被编译为:

function debug() {
  var e
  (e = console).log.apply(null, arguments)
}

这是很奇怪的一种解释方法,为什么要用一个多余的e变量来隔离console和log呢?如果这样编译之后,其结果自然不能被UglifyJS识别,drop_console等选项也就不生效了。解决的办法,就是在调用函数时,直接采用apply。

function debug(...args) {
  console.log.apply(null, args)
}

因为没有使用扩展运算符,所以在编译的时候不会产生上面那种奇怪的分割代码,也就正常被UglifyJS优化了。

10:24:33 已有0条回复
202017.7

UglifyJS里的mangle选项可以设置boolean和object,直观的感觉是,mangle选项让你决定是否把代码里面的变量名进行优化,比如有些变量名很长的,它直接一个字母就替代了,极大的缩短了变量名长度带来的代码量问题,只要在同一个作用域里面,不被外部调用,这种替换非常安全。这一招直接让你的代码缩减巨大,即使你把compress选项设置为false,也能看到显著效果。它还提供更详细的设置选项,你可以选择是否替换toplevel的变量名(默认不替换),也可以有其他选项,具体可以看文档

17:02:23 已有2条回复
  1. mangle 为object 怎么配置呢?
    uglifyJS AST 语法树 混淆 怎么配置 知道吗?
    #850 zhoulujun 2019-10-10 10:55 回复
  2. 请查看官方文档
    #852 回复给#850 否子戈 2019-10-13 09:11 回复
132017.7

Promise catch往后传递

Promise实例有then方法和catch方法,一般用then来处理成功返回数据时的情况,为了把处理后的数据往下一个then传递,通过return一个新数据的方法,让下一个then的参数等于这个新数据。catch方法更有差别,当你调用一次catch之后,后面如果再继续调用catch方法,它们都会被忽略,因为从概念上也可以认为,catch之后,错误已经被捕获了,为了让后面的catch还能生效,和then的return类似,也可以通过一种方法往下传递,但是不是用return,而是用throw:

new Promise((resolve, reject) => reject('a')).catch(err => {
  console.log(err)
  throw err
})
.catch(err => console.log(err))

这样就可以使第二个catch也捕获到错误信息,当然,在第一个catch中,可以通过throw不同的err来传递不同的错误信息给下一个catch。

11:38:33 已有0条回复
132017.6

svg defs pattern fill image

svg里面有时候会用pattern去写一个背景图片,然后在其他元素里面去使用fill: url(#patternId)来调用它,这样就可以实现在一个svg里面定义自己的背景图片,而且还可以使用svg来画这种背景图。

但是有一个问题是,在IE里面,fill调用不支持style属性中使用,比如下面的无效代码:

<rect style="fill: url(#patternId)">

在Chrome下是正常的,但是在IE中使用的时候,没法正常显示,而你需要将fill属性改为attr:

<rect fill="url(#patternId)">

这样才能正常显示你想要的背景图效果。

16:51:31 已有0条回复