js 去除对象指定key 不区分大小写
用loadsh 的omitBy方法
_
此时的 searchResult 是没有任何refid的key的包括各种大小写
用loadsh 的omitBy方法
_
此时的 searchResult 是没有任何refid的key的包括各种大小写
1、背景
spa项目最大的特点就是js随着项目越来越大越来越多,导致拉取js的时间很长,虽然拉取过一次之后都有缓存,但是每次发布总会拉新代码,还是会拉取很慢尤其再网速慢的情况下,现在很多app都内嵌了h5 混合 js拉取慢导致了 app显示就慢 需要提高js加载新能。 虽然现在的spa可以通过拆路由懒加载等解决包太大的问题,但是效果还是不是很理想,当然最终的方案还得SSR啊。
2、一些常用的技术方案
· 减少请求
· 合并公共脚本
· 懒加载资源
· cdn
....
这些常用切正常的操作我们就不多说了 网上文章一大堆,今天来讲下 appcache 缓存解决方案。首先这套appcache的方案已经不推荐了但是这种强缓存的策略还是牛逼的 所以我们可以继续尝试下。
3、appcache方案
1、首先appcache 是离线缓存,即使你没网也会直接访问得到东西。
2、缓存严重也会有问题,比如更新了之后线上代码还是老的
先说下原理:
appcache缓存需要 一个
manifest="./service.appcache"
放到html的标签里面这些就是缓存清单的一些配置 。浏览器会根据清单里面的内容进行缓存。
由于是spa项目基本没有html代码 只有一小段 其他都是js跟css。由于html 是整个缓存的 有可能会缓存原来老的js 跟css 更新不及时的问题, 所以我们把js 跟css 全部放到一个js里面 通过这一个js去加载该版本的js跟css。并且每次版本迭代这个js的随机数都不一样可以保持代码不会错乱掉。
所以最终spa项目需要改2点。第一html模板生成需要把manifest appcache的缓存列表生成好,第二 统一脚本生成好,用来加载核心脚本,基本也就三个 第一 dll或者公共脚本 第二app.js 的入口脚本 第三app.css的公共样式,只需要这三个就行,因为懒加载的脚本是通过app.js入口定的,只要app.js 入口脚本加载好其他的脚本就会加载好。之后appcache会根据列表里面的缓存开始缓存脚本,其他之后的请求就会直接命中缓存。
总结:
1、生成缓存配置文件
2、生成统一拉取js css的核心脚本 带有版本号随机数
3、访问拉取 二次命中缓存 加载速度快
4、pwa也用了但是明显没有 appcache快,还有地段下serviceworks拉取本地脚本会失败的问题
5、缓存配置文件需要同源
6、生成appcache manifest 文件跟生成核心js的代码 可以用webpack或者gulp 按照打包工具不一样自己实现。
最近玩了一下SASS,感觉不错,不过CSS3在不同平台兼容性代码一直是个头痛的问题,手写处理费时费力又容易出错。
曾经一直用sublime text写html和css,这些问题都有相应的插件。用Webstorm写js,但是来回切换编辑器也比较麻烦。
虽然Webstorm内置了css3自动补全功能,当输入user-select时,Webstorm会自动补全:
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
但是很多情况下,这种自动补全并不令人满意,比如当我输入display:flex;时,Webstorm并不会自动补全为:
display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;
Autoprefixer是一个后处理程序,不象Sass以及Stylus之类的预处理器。它适用于普通的CSS,可以实现css3代码自动补全。也可以轻松跟Sass,LESS及Stylus集成,在CSS编译前或编译后运行。详情见,https://github.com/postcss/autoprefixer
当Autoprefixer添加前缀到你的CSS,还不会忘记修复语法差异。这种方式,CSS是基于最新W3C规范产生:
a {background : linear-gradient(to top, black, white);display : flex}::placeholder {color : #ccc}
编译成:
a {background : -webkit-linear-gradient(bottom, black, white);background : linear-gradient(to top, black, white);display : -webkit-box;display : -webkit-flex;display : -moz-box;display : -ms-flexbox;display : flex}:-ms-input-placeholder {color : #ccc}::-moz-placeholder {color : #ccc}::-webkit-input-placeholder {color : #ccc}::placeholder {color : #ccc}
Autoprefixer 同样会清理过期的前缀,因此下面的代码:
a {-webkit-border-radius : 5px;border-radius : 5px}
编译成:
a {border-radius : 5px}
因为经过Autoprefixer处理,CSS将仅包含实际的浏览器前缀。
所以尝试在Webstorm下搜索autoprefixer插件,无果。那就自己手动配置了一个。首先我考虑配置File Watchers,但是不习惯,原来在sublime text下用autoprefixer都是手动触发的,所以后面我配置了External Tools。
(略)
见https://github.com/postcss/autoprefixer:
sudo npm install autoprefixer -g
要不要加sudo,或者是不是全局安装(-g)那就看你自己的环境了。
npm太慢,我是用淘宝的 NPM 镜像的https://npm.taobao.org/
Autoprefixer其实是postcss的插件,见https://github.com/code42day/postcss-cli
sudo npm install postcss-cli -g
打开Webstorm设置,Preferences -> Tools -> External Tools ;点击新增按钮,如图:
填写具体配置,例如我的配置,如图:
Program:填入你的postcss-cli 的PATH;
Parameters: -u autoprefixer -o $FileDir$/$FileName$ $FileDir$/$FileName$ ,你可以根据你自己的需要配置,具体参见https://github.com/code42day/postcss-cli
Working directory :$ProjectFileDir$
配置好后,你可以在css,或sass文件中右键,就可以在右键菜单中看到External Tools – autoprefixer,点击搞定,嘎嘎。
右键太麻烦的话,可以设置个快捷键,打开Webstorm设置,Preferences -> Keymap , 搜索External Tools , 配置 autoprefixer即可。 不要和原来的冲突就可以了。
ps:windows下可以直接用autoprefixer的PATH,具体配置
windows 找不到autoprefixer.cmd,webstrom无法用执行autoprefixer 这个问题,
可以配置
Program:C:\Users\gaojun-pd\AppData\Roaming\npm\postcss.cmd
Parameters:-u autoprefixer -o $FileDir$\$FileName$ $FileDir$\$FileName$
Working directory :$ProjectFileDir$
在文件头部加入
phantom.outputEncoding="GBK";
就能解决 比如
phantom.outputEncoding="GBK";
var casper = require('casper').create();
casper.start('http://www.baidu.com/', function() {
this.echo(this.getTitle());
});
casper.thenOpen('http://www.luqidong.com', function() {
this.echo(this.getTitle());
});
casper.run();
问题出现原因:phantomjs 2.0.0 不稳定用1.9.8 就没问题
解决方案:
1、换1.9.8版本的phantomjs
2、打开casperjs 里面的bootstrap.js 地址在 \bin\里面
然后找到 判断phantomjs 版本的地方
替换成一下代码
(function (version) { // required version check if (version.major === 1) { if (version.minor < 8) { return __die('CasperJS needs at least PhantomJS v1.8 or later.'); } if (version.minor === 8 && version.patch < 1) { return __die('CasperJS needs at least PhantomJS v1.8.1 or later.'); } } else if (version.major === 2) { console.log("Warning PhantomJS v2.0 not yet released. There will not be any official support for any bugs until stable version is released!"); } else return __die('CasperJS needs PhantomJS v1.x or v2.x'); })(phantom.version);
别指望看几篇讲解就能看懂js里面的this。我也是前后翻阅了很多资料最后稍微有点懂的。
javascript里面的this跟大多数语言类似,总是指的一个对象,而具体的指向哪个对象是在运行时基于函数的执行环境动态绑定的,二不是函数被声明时的环境。
基本 this的指向大致分为以下四种
作为对象的方法调用
作为普通函数调用
构造器调用
Function.prototype.call或Function.prototype.apply调用
下面详细讲解下
1、作为对象的方法调用
当函数作为对象的方法调用的时候,this指向该对象
var obj = { a: 1, getA: function () { alert(this === obj);//true alert(this.a);//1 } }; obj.getA();
2、作为普通函数调用
当函数不作为对象的属性被调用的时候,也就是我们常说的普通函数方式,此时this总是指向全局对象,在浏览器的javascript里,这个全局对象就是window对象。
window.name ='globalName'; var getName = function(){ return this.name; }; console.log(getName()); //globalName //or window.name ='globalName'; var myobj ={ name:'sven', getName:function(){ return this.name; } }; myobj.getName() ;//sven var getName = myobj.getName; console.log(getName());// globalName
但是有时候我们会遇到一些困扰,比如在div节点的时间函数内部,有一个局部的callback方法,callback被作为普通函数调用时,callback内部的this指向了window,但是我们往往想让他指向该div节点,代码:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div id="div1">我是一个div</div> <script> window.id = "window"; document.getElementById("div1").onclick = function () { alert(this.id); var callback = function () { alert(this.id); }; callback(); } </script> </body> </html>
此时有一个简单的解决方案,可以用一个变量保存div节点的引用。
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div id="div1">我是一个div</div> <script> window.id = "window"; document.getElementById("div1").onclick = function () { var that =this; alert(this.id); var callback = function () { alert(that.id); }; callback(); } </script> </body> </html>
在ECMAScript 5的 严格模式下,这种情况的this已经被规定为不会指向全局对象,而是undefined。
3、构造器调用
javascript中没有类,但是可以从构造器中创建对象,同事也提供了new的运算符,使得构造器看起来更像一个类。
除了宿主提供一些内置函数,大部分的javascript函数都可以当做构造器使用。构造器的外表跟普通函数一模一样,他们的区别在于被调用的方式,当用new运算符调用函数时,该函数总是会返回一个对象,通常情况下,构造器里的this就指向返回的这个对象,如下代码:
var MyClass = function () { this.name = 'sven'; }; var obj = new MyClass(); alert(obj.name); //sven
但用new 调用构造器时,还要注意一个问题,如果构造器显式地返回一个object类型的对象,那么此次运算结果最终会返回这个对象,而不是我们期待的this:
var MyClass = function () { this.name = 'sven'; return { //显式滴返回了一个对象 name: 'anne' } }; var obj = new MyClass(); alert(obj.name); //anne
如果构造器不显式地返回任何数据,或者是返回一个非对象类型的数据,就不会造成以上的问题:
var MyClass = function () { this.name = 'sven'; return 'anne'; }; var obj = new MyClass(); alert(obj.name); //sven
4、Function.prototype.call或Function.prototype.apply调用
跟普通的函数调用想必,用Function.prototype.call或Function.prototype.apply可以动态第改变传入函数的this:
var obj1 = { name: 'sven', getName: function () { return this.name; } }; var onj2 = { name: 'anne' }; console.log(obj1.getName());//sven console.log(obj1.getName.call(obj2));//anne
call 和 apply的方法能很好滴体验javascript的函数式编程特性,在javascript中,几乎每一次编写函数式风格的代码,都离不开call和apply。
fiddler的断点功能可以截获发送或者接收到的请求,然后更改信息方便我们的调试。对于前端开发工程师来说对发送或者对接受的请求做处理是再正常不过的了下面用fiddler做一个例子来讲解下如何用fiddler做断点调试。
1、断点的位置在界面的底部
点击一下会出现一个箭头朝上的标记,在点击下就会有抄下的标记
第一个是断点的发送请求出去之前,第二个是数据返回的时候截取。
2、我们以www.ly.com为例子:
点击这几个tab标签会请求异步替换掉下面的内容。
我们点击海岛的时候请求的异步里面有2个核心参数一个是method 一个是 typeName 。先断点断在发送求情的时候
然后点击一个tab标签 比如欧洲:如下图
第一个是断点到返回状态,第二个是直接走完,第三个是传到服务器的一些值,我们在这里可以进行更改,然后点击Run to Completion 来完成这个请求,或者点击工具栏上的go按钮来走完全部的请求。当然我们还可以修改请求的头部信息,比如传过去的cookies等。
3、截断请求返回的内容进行修改
由于我们这是返回之后的信息修改,所以返回之前的头信息是无法修改的,点击右侧Texview 就是查看返回的内容,然后在这里是可以修改的. 还有点击右下角在 notepad里面查看这样看起来更方便,修改完之后点击 Run to Completion 走完整个请求的过程,然后查看下状态.
这只是个简单的例子,大家可以举一反三。
未完待续
brew update && brew install phantomjs查看你是否已经安装好了PhantomJS
phantomjs --version
简单的例子
让我们来看一个简单的例子
simple.js
console.log(
"we can log stuff out."
);
function
add(a, b) {
return
a + b;
}
conslole.log(
"We can execute regular JS too:"
, add(1, 2));
phantom.exit();
我们来用下面的命名来运行它
phantomjs simple.js
运行结果
我们在控制台看到了两行输出。当然这个非常简单,但是它反映出一点:PhantomJS可以像一个浏览器那也处理javascript,然而这段代码并没有PhantomJS-specific 代码,但是看最后一行,这个很重要,因为所有的phantomjs执行完之后都要退出,比如我们想再关闭里面写个回调。
加载页面
phantomjs可以帮助我们打开一个页面,并且执行javascript。
例如: script.js
var
page = require(
'webpage'
).create();
console.log(s);
phantom.exit();
});
这里我们利用webpage模块来创建一个webpage对象,然后使用open的方法打开它,里面有2个参数第一个是url,然后就是回调函数,回调函数里面,里面可以输出返回的状态,如上代码执行之后我们在控制台里面看到的应该是"success"。
让我们来做些更有趣的事情,我们打开页面然后执行一段脚本看看:
page.open(
'http://www.ly.com'
,
function
() {
var
title = page.evaluate(
function
() {
var
posts = document.getElementsByClassName(
"logo"
);
posts[0].style.backgroundColor =
"#000000"
;
return
document.title;
});
page.clipRect = { top: 0, left: 0, width: 600, height: 700 };
page.render(title +
".png"
);
未完待续
一、什么是gulp。
gulp和grunt是基于Node.js创建,是一个基于任务的命令行工具,它能够同构减少减少预先需要准备的资源来加速工作流。它将工作包裹进入任务之中,任务会随着你的工作进程自动编译。它与grunt的最大区别就是它充分借鉴了Unix操作系统的管道(pipe)思想,很多人认为,在操作上,它要比Grunt简单。
1、插件职能不够单一
2、插件完成了本不该由插件完成的事情(这个我有点迷糊,为什么说是 things don't need to be plugins?)
3、配置过于复杂
4、由于糟糕的流程控制导致的临时文件/目录
二、安装gulp
1、npm install -g gulp
2、npm install --save-dev gulp 注释:使用–save/–save-dev就可以自动更新package.json
三、使用方法
在项目目录直接新建gulpfile.js文件,gulp就5个方法:task(创建任务),run(跑任务),watch(观察一般文件改的自动运行任务),src(源文件),和dest(输出文件)。
一般前端任务都是一些sass编译、文件合并压缩重命名、制作雪碧图、和脚本检查这几个需要如下插件
gulp-jshint脚本检查 gulp-sass sass编译 gulp-concat 合并 gulp-uglify脚本压缩 gulp-rename重命名 gulp-minify-css css压缩
下面上代码:
/** * 组件安装 * npm install gulp-util gulp-imagemin gulp-ruby-sass gulp-minify-css gulp-jshint gulp-uglify gulp-rename gulp-concat gulp-clean gulp-livereload tiny-lr --save-dev */ // 引入 gulp及组件 var gulp = require('gulp'), //基础库 imagemin = require('gulp-imagemin'), //图片压缩 sass = require('gulp-ruby-sass'), //sass minifycss = require('gulp-minify-css'), //css压缩 jshint = require('gulp-jshint'), //js检查 uglify = require('gulp-uglify'), //js压缩 rename = require('gulp-rename'), //重命名 concat = require('gulp-concat'), //合并文件 clean = require('gulp-clean'), //清空文件夹 tinylr = require('tiny-lr'), //livereload server = tinylr(), port = 35729, livereload = require('gulp-livereload'); //livereload // HTML处理 gulp.task('html', function() { var htmlSrc = './src/*.html', htmlDst = './dist/'; gulp.src(htmlSrc) .pipe(livereload(server)) .pipe(gulp.dest(htmlDst)) }); // 样式处理 gulp.task('css', function () { var cssSrc = './src/scss/*.scss', cssDst = './dist/css'; gulp.src(cssSrc) .pipe(sass({ style: 'expanded'})) .pipe(gulp.dest(cssDst)) .pipe(rename({ suffix: '.min' })) .pipe(minifycss()) .pipe(livereload(server)) .pipe(gulp.dest(cssDst)); }); // 图片处理 gulp.task('images', function(){ var imgSrc = './src/images/**/*', imgDst = './dist/images'; gulp.src(imgSrc) .pipe(imagemin()) .pipe(livereload(server)) .pipe(gulp.dest(imgDst)); }) // js处理 gulp.task('js', function () { var jsSrc = './src/js/*.js', jsDst ='./dist/js'; gulp.src(jsSrc) .pipe(jshint('.jshintrc')) .pipe(jshint.reporter('default')) .pipe(concat('main.js')) .pipe(gulp.dest(jsDst)) .pipe(rename({ suffix: '.min' })) .pipe(uglify()) .pipe(livereload(server)) .pipe(gulp.dest(jsDst)); }); // 清空图片、样式、js gulp.task('clean', function() { gulp.src(['./dist/css', './dist/js', './dist/images'], {read: false}) .pipe(clean()); }); // 默认任务 清空图片、样式、js并重建 运行语句 gulp gulp.task('default', ['clean'], function(){ gulp.start('html','css','images','js'); }); // 监听任务 运行语句 gulp watch gulp.task('watch',function(){ server.listen(port, function(err){ if (err) { return console.log(err); } // 监听html gulp.watch('./src/*.html', function(event){ gulp.run('html'); }) // 监听css gulp.watch('./src/scss/*.scss', function(){ gulp.run('css'); }); // 监听images gulp.watch('./src/images/**/*', function(){ gulp.run('images'); }); // 监听js gulp.watch('./src/js/*.js', function(){ gulp.run('js'); }); }); });
运行的话只需要在工程目录下 gulp yourtaskname 你的任务名就可以了
代码:
var http = require('http');var connect = require('connect');var app = connect() .use(connect.logger('dev')) .use(connect.static('public')) .use(connect.bodyParser()) .use(function(req, res){ res.end(JSON.stringify(req.body)); })http.createServer(app).listen(2081);
报错图:
/home/carl/nodedev/test.js:5 .use(connect.logger('dev')) ^TypeError: Object function createServer() { function app(req, res, next){ app.handle(req, res, next); } merge(app, proto); merge(app, EventEmitter.prototype); app.route = '/'; app.stack = []; return app;} has no method 'logger' at Object.<anonymous> (/home/carl/nodedev/test.js:5:16) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:906:3
原因:
connect更新了 logger更换成了morgan 请看这里 https://www.npmjs.org/package/connect
现在错误日志记录需要用morgan ,引用下 morgan 就行
var logger = require('morgan');
var app = connect().use(logger());