Friends

2015年度总结

2015年完成目标

  • 整站架构优化:
    • 全站JQuery版本升级
    • 网校前端资源迁移至静态服务器
    • 网校前端项目工程化(自动化编译,打包,加hash,静态文件映射)
    • nodeJs中间层渲染技术尝试
    • 组件化开发,抽取公用组件
    • iconfont技术落地
  • 性能优化及监控
    • 网校主要页面性能优化
    • 解决360浏览器默认使用高级内核渲染页面
    • IE6,IE7下添加升级浏览器提示
  • 技术尝试
    • react&redux技术实践
    • knockout,angularJs框架实践
    • 开发及发布流程优化
    • 搭建jenkins自动化发布流程,实现自动打Tag
    • 规范前后端对接流程
  • 组内分享
    • 自动化编译和jenkins自动化发布搭建经验分享
    • angularJs技术分享
    • 2015前端技术峰会总结分享

展望2016

  • 发布流程系统完善
  • 模块化开发体系化
  • 提升hybird app性能及体验
  • 纵向线wiki规范文档补齐
  • 统一产品线UI
  • React Native项目实践
December 31, 2015
Read More

jenkins自动化发布流程配置

持续集成

现有持续集成CI(Continuous integration)管理系统有Jenkins, Travis CI, TeamCity, gitlab CI
持续集成,自动化构建,自动化发布,自动化测试

Travis CI

主要功能就是为开源社区提供免费的CI服务,对于商业用户可以使用Travis Pro版本, Travis CI只支持github极大的限制了其应用场景。但是也由于其只支持github,其把和github的集成做到了极致的平滑,易用,因此,对于本就把github作为代码托管平台的项目来说,Travis CI可以做为第一选择。

jenkins的特点

  • 易安装:仅仅一个 java -jar jenkins.war,从官网下载该文件后,直接运行,无需额外的安装,更无需安装数据库;
  • 易配置:提供友好的GUI配置界面;
  • 变更支持:Jenkins能从代码仓库(Subversion/CVS)中获取并产生代码更新列表并输出到编译输出信息中;
  • 支持永久链接:用户是通过web来访问Jenkins的,而这些web页面的链接地址都是永久链接地址,因此,你可以在各种文档中直接使用该链接;
  • 集成E-Mail/RSS/IM:当完成一次集成时,可通过这些工具实时告诉你集成结果(据我所知,构建一次集成需要花费一定时间,有了这个功能,你就可以在等待结果过程中,干别的事情);
  • JUnit/TestNG测试报告:也就是用以图表等形式提供详细的测试报表功能;
  • 支持分布式构建:Jenkins可以把集成构建等工作分发到多台计算机中完成;
  • 文件指纹信息:Jenkins会保存哪次集成构建产生了哪些jars文件,哪一次集成构建使用了哪个版本的jars文件等构建记录;
  • 支持第三方插件:使得 Jenkins 变得越来越强大;

流程进化过程

切图-->code-->丢给后端
切图-->code-->提交代码-->手动修改版本号-->手动ftp发
更新项目字体库-->code-->提交代码-->前端自动发布-->自动添加版本号
更新项目字体库-->code-->提交代码-->git通知code reviewer审查代码-->审查通过-->通知测试发布项目-->jenkins自动发布到服务器

img

更完善的发布流程

img

持续集成流程

img

优化点

  • 自动构建及发布
  • 自动打标签tag
  • 前后端项目分离
  • 自动更新资源版本

jenkins配置

  • jenkins插件安装
  • jenkins参数化构建
    • 插件:Build WIth Parameters
    • wiki:https://wiki.jenkins-ci.org/display/JENKINS/Build+With+Parameters+Plugin
  • jenkins权限控制
    • 插件:Role Strategy Plugin
    • wiki:https://wiki.jenkins-ci.org/display/JENKINS/Role+Strategy+Plugin
  • 自动化打tag
    • 插件:Zentimestamp Plugin,Git Publisher
    • wiki:http://wiki.jenkins-ci.org/display/JENKINS/Zentimestamp+Plugin
  • 文件发送到服务器:
    • 插件:Publish Over FTP, Publish Over SSH
    • wiki:http://wiki.jenkins-ci.org/display/JENKINS/Publish+Over+FTP+Plugin http://wiki.jenkins-ci.org/display/JENKINS/Publish+Over+SSH+Plugin
  • 多个job之间串并联
    • 插件:Join Plugin, Build Pipeline Plugin
    • wiki:https://wiki.jenkins-ci.org/display/JENKINS/Join+Plugin
  • jenkins邮件扩展版
    • 插件:Email Extension Template Plugin
    • wiki:http://wiki.jenkins-ci.org/display/JENKINS/Email-ext+plugin

img img

生成的mapping json文件

{
    "/class/common/bundle.js":"/class/common/bundle-15c92.js",
    "/class/common/bundle.css":"/class/common/bundle-b2f6b.css",
    "/class/app/courseList/bundle.js":"/class/app/courseList/bundle-15c92.js",
    "/class/app/courseList/bundle.css":"/class/app/courseList/bundle-0d8b6.css"
}

静态资源引用方式

读取mapping json文件找到相应的映射文件

<script src="<%=YesHJ.Class.ClassStaticHelper.GetSource("/class/app/course/bundle.js")%>"></script>

后期优化点

  • 构建前接入code review管理系统
  • 构建接入代码检查测试环节
  • 前后端构建串联发布
  • yz环境发布明细化

继续探索...

December 30, 2015
Read More

多行文字截断-webkit-line-clamp

<!--有一定浏览器兼容性问题-->
<style>
.content{
    overflow : hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
</style>
<div class="content">
    -webkit-line-clamp is an unsupported WebKit property that limits the number of lines of text displayed in a block element. In order to achieve the effect, it needs to be combo-ed with a couple of other exotic WebKit properties.
</div>
September 18, 2015
Read More

Baseline JPEG vs. Progressive JPEG

Baseline JPEG 与 Progressive JPEG的区别

Baseline JPEG是从上往下加载,而Progressive JPEG是从模糊到清晰加载

img

Chrome + Firefox + IE9 下 Progressive JPEG 加载很快
Progressive 比 Baseline 格式小几KB
大于 10K 的图片,Progressive 格式更小 (in 94% of the cases)
小于 10K 的图片,Baseline格式更小(75%)

测试结果: img

查看详细文档

September 12, 2015
Read More

移动端技术数据上报规范

  • 移动端来源区分
    • 所有的上报都需要区分网络状态
      • 格式为 -[网络状态]-
      • 参照mmq返回值
      • 0 - 未知网络
      • 1 - WIFI
      • 2 - 2G
      • 3 - 3G
      • 4 - 4G
    • 根据场景需要,区分手Q 和 其他非手Q数据,微信上报[此处可选]
      • QQ 手机QQ
      • MicroMessager 微信
      • 其他场景自行选择浏览器的user-agent
  • 页面测速(工具化)
    • html 页面需要上报Navigation Timing
      • 参见performance.timing
      • 使用测速系统自动上报点
    • 页面测速需要区分离线包&非离线包
      • pack 离线包
      • unpack 非离线包
    • CGI测速上报mm系统
      • network-[网络状态]-url
    • 页面打点可以自行处理,需要包含以下测速点
      • 页面底部 dom-end
      • js加载完成 js-end
      • js执行完成 js-called-end
      • 数据加载完成 data-load-end
      • 数据渲染完成 data-render-end
      • 首屏速度 first-screen
        • 首屏依赖数据的话,首屏速度参照data-render-end,反之,参照js-called-end
    • 异步加载的文件测速(js/css/第三方资源)
      • 速度上报测速系统
      • 带上网络状态以及离线包情况
      • js-load-xxx/css-load-xxx/img-load-xxx/file-load-xxx
  • 失败率
    • 文件加载失败率(css、js、图片[必要场景])
    • 首屏关键图片监控(失败率/测速/区分首次与非首次)[可选]
  • 日志信息
    • CGI拉取失败错误
      • 信息包含网络状态、错误码、url地址
      • 格式:network-[网络状态]-url
    • 必要的关键路径上报[可选]
    • tryjs堆栈上报(如果有)
    • local 异常上报
September 12, 2015
Read More

触屏自动换算REM

<script>
    //copy from taobao
    !function (win) {
        function refreshRem() {
            var width = docEl.getBoundingClientRect().width;
            width / dpr > 540 && (width = 540 * dpr), win.rem = width / 16, docEl.style.fontSize = win.rem + "px"
        }
        var dpr, scale, tid, doc = win.document, docEl = doc.documentElement, metaEl = doc.querySelector('meta[name="viewport"]'), flexibleEl = doc.querySelector('meta[name="flexible"]');
        if (metaEl) {
            var match = metaEl.getAttribute("content").match(/initial\-scale=(["']?)([\d\.]+)\1?/);
            match && (scale = parseFloat(match[2]), dpr = parseInt(1 / scale))
        } else if (flexibleEl) {
            var match2 = flexibleEl.getAttribute("content").match(/initial\-dpr=(["']?)([\d\.]+)\1?/);
            match2 && (dpr = parseFloat(match2[2]), scale = parseFloat((1 / dpr).toFixed(2)))
        }
        if (!dpr && !scale) {
            var k = (win.navigator.appVersion.match(/android/gi), win.navigator.appVersion.match(/iphone/gi)), devicePixelRatio = win.devicePixelRatio;
            dpr = k ? devicePixelRatio >= 3 ? 3 : devicePixelRatio >= 2 ? 2 : 1 : 1, scale = 1 / dpr
        }
        if (docEl.setAttribute("data-dpr", dpr), !metaEl)if (metaEl = doc.createElement("meta"), metaEl.setAttribute("name", "viewport"), metaEl.setAttribute("content", "initial-scale=" + scale + ", maximum-scale=" + scale + ", minimum-scale=" + scale + ", user-scalable=no"), docEl.firstElementChild) {
            docEl.firstElementChild.appendChild(metaEl);
        }else {
            var l = doc.createElement("div");
            l.appendChild(metaEl), doc.write(l.innerHTML)
        }
        win.dpr = dpr, win.addEventListener("resize", function () {
            clearTimeout(tid), tid = setTimeout(refreshRem, 300)
        }, !1), win.addEventListener("pageshow", function (e) {
            e.persisted && (clearTimeout(tid), tid = setTimeout(refreshRem, 300))
        }, !1), "complete" === doc.readyState ? doc.body.style.fontSize = 12 * dpr + "px" : doc.addEventListener("DOMContentLoaded", function () {
            doc.body.style.fontSize = 12 * dpr + "px"
        }, !1), refreshRem()
    }(window);
</script>
September 12, 2015
Read More

React add-ons

React add-ons

React.addons 是编译react代码的工具方法集合,包含如下方法:

  • TransitionGroup,CSSTransitionGroup 处理动画
  • LinkedStaeMixin 双向绑定的helper改变state的值
  • cloneWithProps 浅复制props和动态改变props
  • createFragment 创建代码块集合
  • update 更新处理数组的helper类
  • PureRenderMixin
  • classSet 处理拼接className非常有用
  • TestUtils
  • Perf

使用方法

引入 react-eith-addons.js 或 require('react/addons')

classSet

// inside some `<Message />` React component
render: function() {
  var classString = 'message';
  if (this.props.isImportant) {
    classString += ' message-important';
  }
  if (this.props.isRead) {
    classString += ' message-read';
  }
  // 'message message-important message-read'
  return <div className={classString}>Great, I'll be there.</div>;
}

上面的处理方式比较冗长,使用classSet()方法处理如下:

render: function() {
  var cx = React.addons.classSet;
  var classes = cx({
    'message': true,
    'message-important': this.props.isImportant,
    'message-read': this.props.isRead
  });
  // same final string, but much cleaner
  return <div className={classes}>Great, I'll be there.</div>;
}

查看官网DOC

September 11, 2015
Read More

React proptypes

属性校验

随着应用的增长,确保你的组件正确使用是有必要的。React允许我们指定propTypes。React.PropTypes声明了一系列的校验确保我们接收的数据是合法的。如果不合法的数据出现在属性当中,控制台会打印警告信息。下面是不同的校验类型:

React.createClass({
  propTypes: {
    // You can declare that a prop is a specific JS primitive. By default, these
    // are all optional.
    optionalArray: React.PropTypes.array,
    optionalBool: React.PropTypes.bool,
    optionalFunc: React.PropTypes.func,
    optionalNumber: React.PropTypes.number,
    optionalObject: React.PropTypes.object,
    optionalString: React.PropTypes.string,

    // Anything that can be rendered: numbers, strings, elements or an array
    // containing these types.
    optionalNode: React.PropTypes.node,

    // A React element.
    optionalElement: React.PropTypes.element,

    // You can also declare that a prop is an instance of a class. This uses
    // JS's instanceof operator.
    optionalMessage: React.PropTypes.instanceOf(Message),

    // You can ensure that your prop is limited to specific values by treating
    // it as an enum.
    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),

    // An object that could be one of many types
    optionalUnion: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.number,
      React.PropTypes.instanceOf(Message)
    ]),

    // An array of a certain type
    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),

    // An object with property values of a certain type
    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),

    // An object taking on a particular shape
    optionalObjectWithShape: React.PropTypes.shape({
      color: React.PropTypes.string,
      fontSize: React.PropTypes.number
    }),

    // You can chain any of the above with `isRequired` to make sure a warning
    // is shown if the prop isn't provided.
    requiredFunc: React.PropTypes.func.isRequired,

    // A value of any data type
    requiredAny: React.PropTypes.any.isRequired,

    // You can also specify a custom validator. It should return an Error
    // object if the validation fails. Don't `console.warn` or throw, as this
    // won't work inside `oneOfType`.
    customProp: function(props, propName, componentName) {
      if (!/matchme/.test(props[propName])) {
        return new Error('Validation failed!');
      }
    }
  },
  /* ... */
});

添加属性默认值

添加自定义属性的默认值

var ComponentWithDefaultProps = React.createClass({
  getDefaultProps: function() {
    return {
      value: 'default value'
    };
  }
  /* ... */
});

查看官网DOC

September 11, 2015
Read More

bat批处理命令

批处理语法

echo 表示显示此命令后的字符
echo off 表示在此语句后所有运行的命令都不显示命令行本身
@与echo
off相象,但它是加在每个命令行的最前面,表示运行时不显示这一行的命令行(只能影响当前行)。
call 调用另一个批处理文件(如果不用call而直接调用别的批处理文件,那么执行完那个批处理文件后将无法返回当前文件并执行当前文件的后续命令)。
pause 运行此句会暂停批处理的执行并在屏幕上显示Press any key to continue... 的提示,等待用户按任意键后继续
rem 表示此命令后的字符为解释行(注释),不执行,只是给自己今后参考用的(相当于程序中的注释)。

@echo off            //不显示后续命令行及当前命令行
dir c://*.* >a.txt       //将c盘文件列表写入a.txt 
call c://ucdos//ucdos.bat   //调用ucdos 
echo 你好            //显示"你好" 
pause              //暂停,等待按键继续 
rem 准备运行wps         //注释:准备运行wps 
cd ucdos            //进入ucdos目录 
wps               //运行wps

批处理参数

%[1-9]表示参数,参数是指在运行批处理文件时在文件名后加的以空格(或者Tab)分隔的字符串。变量可以从%0到%9,%0表示批处理命令本身,其它参数字符串用%1到%9顺序表示。

@echo off
type %1 
type %2

那么运行C://>t a.txt b.txt
%1 : 表示a.txt
%2 : 表示b.txt

批处理条件判断

-if [not] "参数" == "字符串" 待执行的命令,如if "%1"=="a" format a:

参数如果等于(not表示不等,下同)指定的字符串,则条件成立,运行命令,否则运行下一句。

-if [not] exist [路径//]文件名 待执行的命令,如if exist c://config.sys type c://config.sys

如果有指定的文件,则条件成立,运行命令,否则运行下一句。

-if errorlevel <数字> 待执行的命令,如if errorlevel 2 goto x2

很多DOS程序在运行结束后会返回一个数字值用来表示程序运行的结果(或者状态),通过if errorlevel命令可以判断程序的返回值,根据不同的返回值来决定执行不同的命令(返回值必须按照从大到小的顺序排列)。如果返回值等于指定的数字,则条件成立,运行命令,否则运行下一句。

goto

跳到goto所指定的标记处

goto end 

:end 
echo this is the end 

call命令

从一个批处理程序调用另一个批处理程序,并且不终止父批处理程序。

call [[Drive:][Path] FileName [BatchParameters]] [:label [arguments]] 
September 6, 2015
Read More

koa

koa-compose 多个中间件合并

下面是使用.call(this,next),将多个中间件合并:

function *random(next) {
  if ('/random' == this.path) {
    this.body = Math.floor(Math.random()*10);
  } else {
    yield next;
  }
};

function *backwards(next) {
  if ('/backwards' == this.path) {
    this.body = 'sdrawkcab';
  } else {
    yield next;
  }
}

function *pi(next) {
  if ('/pi' == this.path) {
    this.body = String(Math.PI);
  } else {
    yield next;
  }
}

function *all(next) {
  yield random.call(this, backwards.call(this, pi.call(this, next)));
}

app.use(all);

更好的合并方式:

var compose = require('koa-compose'),
    session = require('koa-session'),
    jsonp = require('koa-jsonp'),
    serve = require('koa-static'),
    lusca = require('koa-lusca');

module.exports = function(app) {
    return compose([
        lusca(),
        session(app),
        jsonp(),
        serve(app.config.publicFolder)
    ]);
};
September 2, 2015
Read More

类调用支持fn调用方式

$.fn.huiCalendar = function(options){
  var args = Array.prototype.slice.call(arguments, 1); 
  var res = this; 

  this.each(function(i, _element) { 
    var element = $(_element);
    var calendar = element.data('huiCalendar');
    var singleRes; 

    if (typeof options === 'string') {
      if (calendar && $.isFunction(calendar[options])) {
        singleRes = calendar[options].apply(calendar, args);
        if (!i) {
          res = singleRes; 
        }
        if (options === 'destroy') { 
          element.removeData('huiCalendar');
        }
      }
    }

    else if (!calendar) {
      calendar = new HuiCalendar(element, options);
      element.data('huiCalendar', calendar);
    }
  });

  return res;
};
September 2, 2015
Read More

git add时候报错:LF will be replaced by CRLF

git add时候报错:LF will be replaced by CRLF

报错如下错误 js warning: LF will be replaced by CRLF fatal: CRLF would be replaced by LF

core.autocrlf 设置成false

#备注可以使用--global 也可以不实用,影响不大  
git config --global core.autocrlf true #这个是转换,也是默认值  
git config --global core.autocrlf input #貌似是上库转换,从库中迁出代码不转换  
git config --global core.autocrlf false  #这个一般是window上的,不转换  
September 1, 2015
Read More

React 生命周期

//重复mount一个组件
/* 第一次 render */
getDefaultProps  
getInitialState  
componentWillMount  
render  
componentDidMount  
/* 第二次 render */
componentWillReceiveProps  
shouldComponentUpdate  
componentWillUpdate  
render  
componentDidUpdate 


//先mount后unmount组件
/* mount */
getDefaultProps  
getInitialState  
componentWillMount  
render  
componentDidMount  
/* unmount */
componentWillUnmount  
September 1, 2015
Read More

nginx 安装

mac上安装nginx

下载链接: http://nginx.org/en/download.html
http://nginx.org/download/nginx-1.2.0.tar.gz

//step1: 解压安装文件
tar -xf nginx-1.2.0.tar.gz

//step2: 进入解压目录 
chmod a+rwx *  

//step3: 配置nginx要安装的插件
./configure --user=nginx --group=nginx   --prefix=/opt/nginx  --with-http_realip_module --with-http_addition_module --with-http_gzip_static_module --with-http_random_index_module --with-http_stub_status_module --with-http_sub_module --with-http_dav_module --with-http_perl_module --with-http_ssl_module

//step4: 安装
make && make install

//step5: 启动ngnix
sudo /usr/local/nginx/sbin/nginx

浏览器访问 http://localhost,页面上出现“welcome to nginx!”,说明安装成功!

September 1, 2015
Read More

ES6

let

体现了ES6中的块级作用域的效果,只能在代码块中使用
不会变量提升,所以不能提前调用
在同一作用域中不允许重复申明
不会绑定在window上,所以访问是undefined

const

声明变量和常量,一旦申明,值不能修改,其余的跟let规则
跨模块常量使用export,import 去访问

变量的解构赋值

var [a, b, c] = [1, 2, 3];

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [,,third] = ["foo", "bar", "baz"];
third // "baz"

如下都返回undefined,最后两种情况报错

var [foo] = [];
var [foo] = 1;
var [foo] = false;
var [foo] = NaN;
var [bar, foo] = [1];
// 报错
let [foo] = undefined;
let [foo] = null;

字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

函数参数的解构赋值

function add([x, y]){
  return x + y;
}

add([1, 2]) // 3
//指定函数的默认值
function move({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]

从函数返回多个值

//返回一个数组

function example() {
  return [1, 2, 3];
}
var [a, b, c] = example();

// 返回一个对象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
var { foo, bar } = example();

对象的扩展

function getPoint() {
  var x = 1;
  var y = 10;

  return {x, y};
}

getPoint()
// {x:1, y:10}

class基本语法

与ES5一样,实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。

//定义类
class Point {

  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '('+this.x+', '+this.y+')';
  }

}

var point = new Point(2, 3);

point.toString() // (2, 3)

point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true

不存在变量提升

Class不存在变量提升(hoist),这一点与ES5完全不同。

new Foo(); // ReferenceError
class Foo {}

class 继承

class ColorPoint extends Point {

  constructor(x, y, color) {
    super(x, y); // 调用父类的constructor(x, y),如果没有写constructor方法,会非显式定义constructor
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); // 调用父类的toString()
  }

}
August 29, 2015
Read More

变量提升

ES6新增了let命令,用来声明变量,它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。let不像var那样,会发生“变量提升”现象。

声明提升

当前作用域内的声明都会提升到作用域的最前面,包括变量和函数的声明

(function(){
  var a = "1";
  var f = function(){};
  var b = "2";
  var c = "3";
})();

变量a,f,b,c的声明会被提升到函数作用域的最前面,类似如下:

(function(){
  var a,f,b,c;
  a = "1";
  f = function(){};
  b = "2";
  c = "3";
})();

请注意函数表达式并没有被提升,这也是函数表达式与函数声明的区别。进一步看二者的区别:

(function(){
  //var f1,function f2(){}; //hoisting,被隐式提升的声明

  f1(); //ReferenceError: f1 is not defined
  f2();

  var f1 = function(){};
  function f2(){}
})();

上面代码中函数声明f2被提升,所以在前面调用f2是没问题的。虽然变量f1也被提升,但f1提升后的值为undefined,其真正的初始值是在执行到函数表达式处被赋予的。所以只有声明是被提升的。

August 28, 2015
Read More

深度克隆

deepClone = function(obj) { //deep clone a plain object
    var input = __slice.call(arguments, 1),
        key,
        value;
    for (var i = 0, length = input.length; i < length; i++) {
        for (key in input[i]) {
            value = input[i][key];
            if (input[i].hasOwnProperty(key) && value !== undefined) {
                // Clone objects
                if (__isPlainObject(value)) {
                    obj[key] = __isPlainObject(obj[key]) ?
                        __extend({}, obj[key], value) :
                        // Don't extend strings, arrays, etc. with objects
                        __extend({}, value);
                    // Copy everything else by reference
                } else {
                    obj[key] = value;
                }
            }
        }
    }
    return obj;
}
August 27, 2015
Read More

promise and generator

promise

现在chrome,firefox等高级浏览器已经内置Promise对象,提供两个方法:

Promise.reject()
Promise.resolve()

when.js 丰富了API

jQuery中,很多的操作都返回的是Deferred或promise,如animate、ajax:

// animate  
$('.box')  
    .animate({'opacity': 0}, 1000)  
    .promise()  
    .then(function() {  
        console.log('done');  
    });  

// ajax  
$.ajax(options).then(success, fail);  
$.ajax(options).done(success).fail(fail);  

// ajax queue  
$.when($.ajax(options1), $.ajax(options2))  
    .then(function() {  
        console.log('all done.');  
    }, function() {  
        console.error('There something wrong.');  
    });  

Promise/A+规范

  • 一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)
  • 一个promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换,同时“完成”态和“拒绝”态不能相互转换
  • promise必须实现then方法(可以说,then就是promise的核心),而且then必须返回一个promise,同一个promise的then可以-调用多次,并且回调的执行顺序跟它们被定义时的顺序一致
  • then方法接受两个参数,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用。同时,then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象。
August 24, 2015
Read More

Object.defineProperty

Object.getOwnPropertyDescriptor 获取描述属性特性的描述符对象

// Create a user-defined object.
var obj = {};

// Add a data property.
obj.newDataProperty = "abc";

// Get the property descriptor.
var descriptor = Object.getOwnPropertyDescriptor(obj, "newDataProperty");

// Change a property attribute.
descriptor.writable = false;
Object.defineProperty(obj, "newDataProperty", descriptor);

Object.defineProperty 用于添加或修改属性

var _createClass = (function() {
    function defineProperties(target, props) {
        for (var i = 0; i < props.length; i++) {
            var descriptor = props[i];
            descriptor.enumerable = descriptor.enumerable || false;
            descriptor.configurable = true;
            if ('value' in descriptor) descriptor.writable = true;
            Object.defineProperty(target, descriptor.key, descriptor);
        }
    }
    return function(Constructor, protoProps, staticProps) {
        if (protoProps) defineProperties(Constructor.prototype, protoProps);
        if (staticProps) defineProperties(Constructor, staticProps);
        return Constructor;
    };
})();

查看MDN官方文档

August 19, 2015
Read More

转化成amd

<script>
    (function (factory) {
        if (typeof define === 'function' && define.amd) {
            // AMD (Register as an anonymous module)
            define(['jquery'], factory);
        } else if (typeof exports === 'object') {
            // Node/CommonJS
            module.exports = factory(require('jquery'));
        } else {
            // Browser globals
            factory(jQuery);
        }
    }(function($){
        // 待转化库
    }));
</script>
August 17, 2015
Read More

前端加载性能优化方案

一. 加载性能优化方案

1.服务器端访问优化

Gzip压缩项目文件大小

CDN加速,加快资源的访问速度

分布式静态服务器请求静态文件,设置浏览器缓存

2.HTTPS请求优化

保证请求资源尽量小

减少文件数量,减少文件请求

3.浏览器端渲染优化

1) DOM加载优化

避免使用iframe,阻塞父级页面onload

精简DOM结构

2)图片加载优化

初始首屏之外的图片资源需延迟加载

图片使用CSS Sprites 或 DATA URL 尽量不使用图片,如果可以使用css3实现

显示设置图片宽高,避免页面repaint 图片压缩,尽量使用JPGE,PNG8,如果图片超过50k,考虑叫设计进行优化

针对不同的设备,用media query调用不同size的图片

根据不同的网络状况,调用不同size的图片

3)css加载优化

合并css文件

使用高性能css选择器

使用css3代理js动画处理,使用translate3d开启GPU动画加速

禁止使用@import引入css文件

避免在低端机上使用大量CSS3渐变阴影效果,可考虑降级效果来提升流畅度

4)js加载优化

合并压缩js文件

单页面应用(SPA)考虑延迟加载非首屏业务模块

不可见Tab页延迟加载

避免使用大型类库

基础类库推荐使用zepto

尽可能使用事件代理,避免批量绑定事件

编写高性能javascript

5)浏览器端数据缓存

使用localStorage进行数据缓存

二. 响应性能优化方案

1.避免使用click事件,避免 iOS 300+ms 点击延时问题

2.避免触发页面重绘restyle,repaint,relayout的操作,注意DOM元素的循环操作

3.小心连续触发的事件scroll/resize/touchmove,避免高频繁触发执行

三. 性能检测方案

使用阿里测,YSlow做性能检测

在线分析:https://developers.google.com/speed/pagespeed/insights/?url=www.souche.com

一些指导原则比较老,不一定准确。

可以使用chrome插件:pagespeed,里面的指导原则比较新:

https://chrome.google.com/webstore/detail/gplegfbjlmmehdoakndmohflojccocli

August 10, 2015
Read More

前端知识体系

自己整理了一张前端知识体系图,在业界整理的体系图基础上添加了很多自己梳理的,应该比较全面

前端知识体系

补充腾讯的一张前端知识体系图

前端知识体系

August 10, 2015
Read More

各种mobile浏览器meta设置

<!-- 启用360浏览器的极速模式(webkit) -->

<meta name="renderer"content="webkit">

<!-- 避免IE使用兼容模式 -->

<meta http-equiv="X-UA-Compatible"content="IE=edge">

<!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 -->

<meta name="HandheldFriendly"content="true">

<!-- 微软的老式浏览器 -->

<meta name="MobileOptimized"content="320">

<!-- uc强制竖屏 -->

<meta name="screen-orientation"content="portrait">

<!-- QQ强制竖屏 -->

<meta name="x5-orientation"content="portrait">

<!-- UC强制全屏 -->

<meta name="full-screen"content="yes">

<!-- QQ强制全屏 -->

<meta name="x5-fullscreen"content="true">

<!-- UC应用模式 -->

<metaname="browsermode"content="application">

<!-- QQ应用模式 -->

<metaname="x5-page-mode"content="app">

<!-- windows phone 点击无高光 -->

<metaname="msapplication-tap-highlight"content="no">
August 10, 2015
Read More

命令大全

gem 命令

gem sources --remove https://rubygems.org/  //删除

gem sources -a https://ruby.taobao.org/  //添加

gem sources -l  //查看列表

vi 命令

进入vi的命令 vi filename :打开或新建文件,并将光标置于第一行首 vi +n filename :打开文件,并将光标置于第n行首 vi + filename :打开文件,并将光标置于最后一行首 vi +/pattern filename:打开文件,并将光标置于第一个与pattern匹配的串处 vi -r filename :在上次正用vi编辑时发生系统崩溃,恢复filename vi filename....filename :打开多个文件,依次进行编辑

移动光标类命令 h :光标左移一个字符 l :光标右移一个字符 space:光标右移一个字符 Backspace:光标左移一个字符 k或Ctrl+p:光标上移一行 j或Ctrl+n :光标下移一行 Enter :光标下移一行 w或W :光标右移一个字至字首 b或B :光标左移一个字至字首 e或E :光标右移一个字至字尾 ) :光标移至句尾 ( :光标移至句首 }:光标移至段落开头 {:光标移至段落结尾 nG:光标移至第n行首 n+:光标下移n行 n-:光标上移n行 n$:光标移至第n行尾 H :光标移至屏幕顶行 M :光标移至屏幕中间行 L :光标移至屏幕最后行 0:(注意是数字零)光标移至当前行首 $:光标移至当前行尾

屏幕翻滚类命令 Ctrl+u:向文件首翻半屏 Ctrl+d:向文件尾翻半屏 Ctrl+f:向文件尾翻一屏 Ctrl+b;向文件首翻一屏 nz:将第n行滚至屏幕顶部,不指定n时将当前行滚至屏幕顶部。

插入文本类命令 i :在光标前 I :在当前行首 a:光标后 A:在当前行尾 o:在当前行之下新开一行 O:在当前行之上新开一行 r:替换当前字符 R:替换当前字符及其后的字符,直至按ESC键 s:从当前光标位置处开始,以输入的文本替代指定数目的字符 S:删除指定数目的行,并以所输入文本代替之 ncw或nCW:修改指定数目的字 nCC:修改指定数目的行

删除命令 ndw或ndW:删除光标处开始及其后的n-1个字 do:删至行首 d$:删至行尾 ndd:删除当前行及其后n-1行 x或X:删除一个字符,x删除光标后的,而X删除光标前的 Ctrl+u:删除输入方式下所输入的文本

搜索及替换命令 /pattern:从光标开始处向文件尾搜索pattern ?pattern:从光标开始处向文件首搜索pattern n:在同一方向重复上一次搜索命令 N:在反方向上重复上一次搜索命令 :s/p1/p2/g:将当前行中所有p1均用p2替代 :n1,n2s/p1/p2/g:将第n1至n2行中所有p1均用p2替代 :g/p1/s//p2/g:将文件中所有p1均用p2替换

选项设置 all:列出所有选项设置情况 term:设置终端类型 ignorance:在搜索中忽略大小写 list:显示制表位(Ctrl+I)和行尾标志($) number:显示行号 report:显示由面向行的命令修改过的数目 terse:显示简短的警告信息 warn:在转到别的文件时若没保存当前文件则显示NO write信息 nomagic:允许在搜索模式中,使用前面不带“\”的特殊字符 nowrapscan:禁止vi在搜索到达文件两端时,又从另一端开始 mesg:允许vi显示其他用户用write写到自己终端上的信息

最后行方式命令 :n1,n2 co n3:将n1行到n2行之间的内容拷贝到第n3行下 :n1,n2 m n3:将n1行到n2行之间的内容移至到第n3行下 :n1,n2 d :将n1行到n2行之间的内容删除 :w :保存当前文件 :e filename:打开文件filename进行编辑 :x:保存当前文件并退出 :q:退出vi :q!:不保存文件并退出vi :!command:执行shell命令command :n1,n2 w!command:将文件中n1行至n2行的内容作为command的输入并执行之,若不指定n1,n2,则表示将整个文件内容作为command的输入 :r!command:将命令command的输出结果放到当前行

May 7, 2015
Read More

mac 终端安装权限问题

问题

终端报错:Please try running this command again as root/Administrator.

解决方法

运行命令:sudo chown -R $USER /usr/local

sudo是给与暂时的root权限,chown是change owner改变文件的归属者。 -r一般是递归 这个就是把~/sites/testsite 文件夹和他的子文件都变成 _www用户的

sudo -s 切换到管理员权限命令

也可以运行命令时前面添加sudo,表示以管理员的权限运行命令,如:

sudo npm install compass

May 5, 2015
Read More

grunt compass编译报错

问题

grunt compass编译终端报错:grunt compass Error: invalid option --sourcemap

原因

sass版本问题

解决方法

gem list 查看sass版本,要求sass >= 3.3

如果低于该版本就gem update sass, 一般存在依赖比如compass依赖sass

所以最好gem uninstall compass,sass

再重新安装 gem install sass

ok, 重新运行grunt server 搞定

April 28, 2015
Read More

React Mixins

什么是React Mixins

Mixins 作用抽离出公用代码,供多react组件使用

tips

Mixins里也可以编写组件生命周期的方法,需要注意的是:Mixins里的方法并不会覆盖组件的生命周期方法,会在先于组件生命周期方法执行。
除了生命周期方法可以重复以外,其他的方法都不可以重复,否则会报错

var LogMixin = {
    componentWillMount: function () {
        console.log('Component will mount');
    },
    componentDidMount: function () {
        console.log('Component did mount');
    }
};

var AComponent = React.createClass({
    mixins: [LogMixin],
    render: function () {
        return (
            <div>AComponent</div>
        )
    }
});
April 25, 2015
Read More

onorientationchange设备兼容性处理

(function(){  
    var supportOrientation=(typeof window.orientation == "number" && typeof window.onorientationchange == "object");  

    var updateOrientation=function(){  
        if(supportOrientation){  
            updateOrientation=function(){  
                var orientation=window.orientation;  
                switch(orientation){  
                    case 90:  
                    case -90:  
                        orientation="landscape";  
                        break;  
                    default:  
                        orientation="portrait";  
                }  
                document.body.parentNode.setAttribute("class",orientation);  
            };  
        }else{  
            updateOrientation=function(){  
                var orientation=(window.innerWidth > window.innerHeight)? "landscape":"portrait";  
                document.body.parentNode.setAttribute("class",orientation);  
            };  
        }  
        updateOrientation();  
    };  

    var init=function(){  
        updateOrientation();  
        if(supportOrientation){  
            window.addEventListener("orientationchange",updateOrientation,false);  
        }else{      
            window.setInterval(updateOrientation,5000); 
        }  
    };  

    window.addEventListener("DOMContentLoaded",init,false);  
})();  

December 17, 2014
Read More

经典前端面试题

HTTP状态码

HTTP状态码速记

HTTP请求头

HTTP请求头详解

从输入url到页面加载都发生了什么事

  • 解析域名(host,缓存,DNS域名解析服务器)
  • 浏览器传输层建立TCP连接
  • 浏览器向服务器发送请求命令
  • 三次握手操作
  • 服务器构建并响应(返回响应头及内容)
  • 服务器断开连接
  • 浏览器构建DOM树
  • 浏览器构建Render树
  • 浏览器加载图片,媒体等静态资源
  • 浏览器渲染Render树

cookie,localstorage,sessionstorage的区别

  • localstorage,sessionstorage的每个域名每个端口的缓存限制是5M;cookie每个domain只能有20条cookie,每条cookie的限制是4k,IE下是2k
  • localstorage是永久存储,永不失效除非手动删除,属于持久保存;cookie是跟着页面走的; sessionstorage关掉页面就消失,属于非持久保存
  • cookie会在客户端和浏览器端进行传递,localstorage和sessionstorage只存在本地
  • sessionstorage在同域同窗口中共享,localstorage和cookie是在同源窗口中共享,不同窗口也可以共享
  • localstorage和sessionstorage自己拥有setItem,getItem等API;而cookie需要自己封装响应的API
  • localstorage和sessionstorage不支持IE7及以下浏览器不支持,cookie低版本浏览器也可以支持

doctype的几种模式

strict(严谨模式),transitional(过渡模式),frameset(框架模式)使用的是html 4.0.1的规范
怪异模式是使用浏览器自己的方式解析,因此不同的浏览器不一样,所以称为诡异模式,如果doctype没有设置,会采用怪异模式渲染

jsonp实现原理

var callbackName = 'iAmTheCallback';
window[callbackName] = function (uuu, vvv, www) {
// 对返回的数据做后续处理
}
var script = document.createElement('script');
script.src = 'http://melon.github.io/xxx/yyy?callback='+callbackName;
document.body.appendChild(script);

grunt与gulp的区别

  • gulp使用node stream,使用.pipe()方法使数据从上游流下
  • gulp相比grunt设计的更好,需要很少的配置,而且很快,api简单,易学,核心设计基于unix流的概念,各个功能通过六进行整合并完成复杂的任务
  • gulp使用代码优于配置的策略,维护gulp就像写代码,遵循commonjs规范,因此跟写node没有什么区别
  • grunt在I/O过程中会产生一些中间态的临时文件,一些任务生成临时文件,其他任务可能会基于临时文件再做处理并生成最终文件
  • gulp利用流的方式进行文件处理,通过管道将多个任务链接起来,只有一次I/O操作

为什么使用流:
如果不使用流,读取文件的时候会缓存在内存中,使用fs.createReadStream替代fs.readFile, steam可以让node读取文件一定量的时候就开始向客户端发送响应的内容,无需服务器缓存
资料参考

捕获与冒泡及IE兼容性区别

DOM的事件模型(DOM事件流):捕获型事件和冒泡型事件z
事件捕获阶段:事件从最上一级标签开始往下查找,直到捕获到事件目标(target)。
事件冒泡阶段:事件从事件目标(target)开始,往上冒泡直到页面的最上一级标签。
IE只支持事件冒泡
支持W3C标准的浏览器通过addEventListener(event,fn,useCapture)方法的第三个参数来区分是事件冒泡还是事件捕获,不支持W3C标准的浏览器通过attachEvent()方法,默认是事件冒泡时执行,所以要兼容,只能使用addEventListener,并设置useCapture为false

解决跨域访问的几种方法

jsonp、 document.domain+iframe、window.name、window.postMessage、服务器上设置代理页面
其中html5中提供的postMessage不能兼容IE,postMessage传递的参数有data,source,origin(协议+主机+端口号) 同源的话是通过contentWindow获取子窗口元素,通过window.parent获取父窗口

对象的几种创建方法

js实现深度克隆

Object.prototype.deepClone = function(obj){
  var newObj = {};
  if(typeof(obj) !== "object" || obj === null){
    return obj;
  }
  if(obj instanceof(Array)){

  }else{

  }
}

js实现数组消重

Array.prototype.unique = function (){
  var arrayList = {},
      newArray = [];

  for (var i = 0; i < this.length; i++) {
    if(!arrayList[this[i]]){
      arrayList[this[i]] = true;
      newArray.push(this[i]);
    }
  }

  return newArray;
}

DOM操作-怎样添加、移除、移动、复制、创建和查找节点

  • 添加节点 createElement,createDocumentFragment,createTextNode
  • 插入节点 appendChild,insertBefore
  • 删除节点 removeChild
  • 替换节点 replaceChild
  • 获取父节点 parentNode

快速排序算法

JQuery源码相关

typeof与instanceof的区别

typeof是检查数据类型,返回字符串,instanceof是测试一个对象是否是原型链构造函数的属性,更形象的说话是判断proto是否是指向同一个对象的prototype,返回boolen

浏览器兼容性举例

  • 通过*{margin:0;padding:0}重置不同浏览器下margin,padding不一致的问题
  • float元素同时设置margin在ie6下margin加倍,通过设置display:inline将其转化为行内元素结束
  • min-height兼容性问题,通过ie下设置height方式解决
  解决方法:
  (1).abc{border:1px blue solid;width:200px;height:200px;}
          html>body .abc{width:auto;height:auto;min-width:200px;min-height:200px;}
  (2).abc{width:200px;height:200px;_width:200px;_height:200px;}

因为ie6有一个特征,当定义一个高度时,如果内容超过高度,元素会自动调整高度。

  • ie6下默认有行高 解决方法:overflow:hidden;或font-size:0;
  • opacity不透明兼容性问题 解决方法:filter: alpha(opacity = 80)
  • 火狐不识别background-position-x,background-position-y
  • 两个块元素,竖向的margin不会增加,会叠加,间距为最大的margin

AMD,CMD,CommonJs规范之间的区别

AMD是依赖提前加载 CMD是依赖就近加载 commonJs是同步加载,适合用于服务器端使用,然而现在webpack也使用该规范在客户端

reflow & repaint

display:none 会产生reflow,而visibility:hidden 只会发生repaint, repaint是dom节点的外观改变,reflow是布局发生改变
如下情况会发生reflow:

  • 改变窗口的大小
  • 改变文字大小
  • 增加/删除样式表
  • 内容的改变
  • 激活伪类
  • 操作class属性
  • 脚本操作dom
  • 设置style属性
  • 计算offsetwidth和offsetheight

js有哪些常见的兼容性

  • 阻止冒泡 W3C: e.stopPropagation() IE: return false
  • 阻止默认事件 W3C: e.preventDefault() IE: e.returnValue = false
  • 事件绑定:W3C: addEventListener() IE: attachEvent()
  • 事件解绑:W3C: removeEventListener() IE: detachEvent()
  • event对象: W3C: event IE: window.event
  • 获取target: W3C: e.target IE: e.srcElement
  • 获取keycode: W3C: keycode IE: which

generator与promise

利用localStorage怎么优化触屏端性能

application cache(离线缓存策略),建立manifest文件,通过存储文件的ETag和文件路径,判断文件是否需要更新

HTTP请求响应头中关于缓存的对应关系

服务器端ETag和Last-Modified都是同样的效果,为了在服务器端验证文件是否修改

  • If-None-Match/ETag
  • If-Modified-Since/Last-Modified
  • Cache-Control/Expries Expries是绝对时间,Cache-Control是相对时间

webpack的优势是什么

webpack是德国开发者开发的模块加载器,所有的资源如js,css,images都当做模块,来使用和引用

  • 模块化开发思想,并使用commonJs和AMD规范
  • 丰富的loader插件,支持扩展强大的功能
  • 快速编译,使用异步IO及多级缓存,提高编译效率
  • 可以跟React配合使用,支持热插拔

React的优势是什么

  • 虚拟DOM,当需要更新DOM节点,通过DOM diff算法替换,以最小粒度更新
  • 单向数据绑定
  • JSX,书写上可以把html内嵌到js文件中,更好的进行了封装
  • React与Angular最大的区别是单向数据绑定跟双向数据绑定的区别
  • Angular是MV*框架,是一个完整的框架,而React是实现可重复使用的view

XSS与CSRF

XSS:就是脚本注入问题,获取到用户的相关信息,然后通过自己架设一个网站,让用户提交,随后以数据库的方式记录在攻击者自己的服务器上 解决方法:将用户输入的内容进行过滤

CSRF:伪造请求,冒充用户在站内的操作 (XSS只是CSRF其中一种) 解决方法:通过token令牌,保存在session里,访问接口的时候隐性传到服务器上进行比较

js算出字符串的字节数

var str='我我我';
var bytesCount;
for (var i = 0; i < str.length; i++)
{
  var c = str.charAt(i);
  if (/^[\u0000-\u00ff]$/.test(c)){
    bytesCount += 1;
  } else {
    bytesCount += 2;
  }
}
alert(bytesCount);
//结果是6
//原理也很简单,用正则判断是不是中文,如果是的话,字节数就加1。

ajax原理

Ajax的工作原理相当于在用户和服务器之间加了—个中间层,使用户操作与服务器响应异步化。这样把以前的一些服务器负担的工作转嫁到客户端,利于客户端闲置的处理能力来处理,减轻服务器和带宽的负担,从而达到节约ISP的空间及带宽租用成本的目的。 通过XMLHttpRequest向服务器端发送请求,通过onreadystatechange去监听服务器返回的数据,当readyState为400,state为200的时候,通过responseText获取返回数据

常用的两种继承方式是什么

类继承和原型链继承

js动态创建一个table(主要考察基本DOM操作)

var table = document.createElement("table");

table.setAttribute("id","table");
var tr1 = table.insertRow();
var td1 = tr1.insertCell();
td1.width = "200px";
td1.height = "200px";
td1.innerHTML = "内容";
document.body.appendChild(table);

js原生获取屏幕宽度,滚动高度,元素位置

nodeJs篇

用nodeJS实现启一个服务

var http = require("http");

http.createServer(function(request, response){
    response.writeHead(200,{"Content-Type","text/html"});
    response.end("hello world");
}).listen(3000);
var http = http.createListen();

用nodeJS实现文件copy


React篇

react生命周期

  • 第一次渲染
    • getDefaultProps
    • getInitialState
    • componentWillMount
    • render
    • componentDidMount
  • 重新渲染
    • componentWillReceiveProps
    • shouldComponentUpdate
    • componentWillUpdate
    • componentDidUpdate
  • 摧毁
    • componentWillUnmount
November 11, 2014
Read More

HTTP 状态码

  • 100 continue
  • 200 success
  • 201 created
  • 202 accepted
  • 204 no content
  • 300 multiple choice
  • 301 move permanently
  • 302 found
  • 304 not modified
  • 307 temporary redirect
  • 400 bad request
  • 401 unauthorized
  • 403 forbidden
  • 404 not found
  • 408 request timeout
  • 409 conflict
  • 500 internal server error
  • 502 bad gateway
  • 503 service unavailable
October 2, 2014
Read More

内存泄露

最近几年中,许多浏览器都改善了在页面加载过程中从 JavaScript 回收内存的能力。但是,并不是所有浏览器都具有相同的运行方式。Firefox 和旧版的 Internet Explorer 都存在过内存泄漏,而且内存泄露一直持续到浏览器关闭。

泄露场景

循环引用

var obj = document.getElementById("btn");
obj.a = document.getElementById("btn");

Javascript闭包

var a = function() {
  var largeStr = new Array(1000000).join('x');
  return function() {
    return largeStr;
  }
}();

DOM泄露

当原有的COM被移除时,子结点引用没有被移除则无法回收。

var select = document.querySelector;
var treeRef = select('#tree');

//在COM树中leafRef是treeFre的一个子结点
var leafRef = select('#leaf');  
var body = select('body');

body.removeChild(treeRef);

//#tree不能被回收入,因为treeRef还在
//解决方法:
treeRef = null;

//tree还不能被回收,因为叶子结果leafRef还在
leafRef = null;

//现在#tree可以被释放了。

定时器泄露

定时器也是常见产生内存泄露的地方:

for (var i = 0; i < 90000; i++) {
  var buggyObject = {
    callAgain: function() {
      var ref = this;
      var val = setTimeout(function() {
        ref.callAgain();
      }, 90000);
    }
  }

  buggyObject.callAgain();
  //虽然你想回收但是timer还在
  buggyObject = null;
}

heap profile检测方法

img

September 3, 2014
Read More

href中各种空置比较

<a href="####">#### 增加历史记录,破坏url</a><br>

<a href="####" onclick="location.href='http://www.baidu.com';return false;">#### 缺点同上,其余没有问题</a><br>

<a href="javascript:void(0);" onclick="location.href='http://www.baidu.com';return false;">javascript:void(0);(动态gif停止播放)如果不加return false , ie6下链接不跳转</a><br>

<a href="javascript:;" onclick="location.href='http://www.baidu.com';return false;">javascript:void(0),只是比它更简洁</a><br>

<a href="#">#跳到页面顶部</a><br>

结论是#### return false 与 javascript:; return false 都没有问题,只是javascript:; 较 #### 更严谨

September 2, 2014
Read More

js 基础知识巩固

== 与 === 的区别

1、对于string,number等基础类型,==和===是有区别的

1)不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等

2)同类型比较,直接进行“值”比较,两者结果一样

2、对于Array,Object等高级类型,==和===是没有区别的

进行“指针地址”比较

3、基础类型与高级类型,==和===是有区别的

1)对于==,将高级转化为基础类型,进行“值”比较

2)因为类型不同,===结果为false

null 与 undefined的比较

null==undefined为真,但是null===undefined为假

如果申明的变量未初始化,则访问的值为undefined

调用函数,如果函数没有返回值时,默认返回undefined。

null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。

var a = {class: "Animal", name: 'Fido'}; a.class

chrome可以输出属性值,但是在IE下面是不能输出值,因为class不能作为key键

正则表达式不能进行比较

August 28, 2014
Read More

html5 重力感应

deviceorientation和 MozOrientation(firefox)
deviceorientation事件可获得三个值alpha,beta,gamma,分别代表绕Z轴的
旋转角度(0~360),绕X轴的旋转角度(-180~180),绕Y轴的旋转角度(-90~90)
MozOrientation事件中可获得三个值z,x,y,分别代表垂直加速度,左右的
斜角度,前后的倾斜角度(取值范围:-1~1

浏览器兼容性处理

window.addEventListener('deviceorientation', orientationListener, false); //方向感应器      
window.addEventListener('MozOrientation', orientationListener, false); //方向感应器 for firefox          
window.addEventListener('devicemotion', orientationListener, false); //重力加速感应器 for iphone, android 

三个旋转方向,z,x,y轴,对应分别是:Alpha,Beta,Gamma

function orientationListener(event) {
  var absolute = event.absolute;
  var alpha    = event.alpha;
  var beta     = event.beta;
  var gamma    = event.gamma;
  ...
}

w3c api:http://w3c.github.io/deviceorientation/spec-source-orientation.html
鬼道分享ppt: http://2014.jsconf.cn/slides/luics-hybrid-api.html
实例:http://www.html5tricks.com/demo/html5-ball-pool/index.html
http://www.pjhome.net/web/Orientation.html

August 22, 2014
Read More

sass config.rg 设置说明

开发环境

environment = :development

environment = :production

调试开关

firesass = false

firesass = true

定义本地文件

cssdir = "css"
sass
dir = "sass"
extensionsdir = "sass-extensions"
images
dir = "images"
javascriptsdir = "js"
line
comments = false 设置是否显示行信息

绝对路径

relative_assets = true

压缩比例

output_style = (environment == :development) ? :expanded : :compressed

调试信息

sassoptions = (environment == :development && firesass == true) ? {:debuginfo => true} : {}

August 21, 2014
Read More

Media Query

Media Type媒体类型

<link href="css/reset.css" rel="stylesheet" type="text/css" media="screen" />"

media 属性值

screen:计算机屏幕(默认)
tty:电传打字机以及类似的使用等宽字符网格的媒介
tv: 电视机类型设备(低分辨率、有限的滚屏能力)
projection:放映机
handheld:手持设备(小屏幕、有限带宽)
print: 打印预览模式/打印页面
braille:盲人点字法反馈设备
aural:语音合成器
all:适用于所有设备

Media Query

<link rel="stylesheet" media="only screen and (max-width: 600px)" href="small.css" />
<link rel="stylesheet" media="(min-device-width: 600px) and (max-device-width: 1000px)" href="small.css" />
<link rel="stylesheet" media="not print and (max-width: 600px)" href="small.css" />
<link rel="stylesheet" media="screen and (max-width: 600px) and (orientation: landscape)" href="small.css" />

@media screen and (max-width: 1000px){
    body{
        background: red;
    }
}
@media screen and (max-width: 1000px) and (orientation: landscape){
    body{
        background: yellow;
    }
}
August 20, 2014
Read More

MongoDB

什么是MongoDB

MongoDB是面向文档存储型数据库,NOSQL数据库

doc命令

>db //检查当前数据库
mydb

>use mydb  //新建,切换数据库
switched to db mydb

>show dbs  //查看数据库列表,只有新建DB中插入一条数据才能看见新建的数据库
local     0.78125GB
mydb       0.23012GB
test      0.23012GB

>db.dropDatabase() //删除数据库

>db.createCollection("movie") //创建集合,相当于关系型数据库中的table
{ "ok" : 1 }

>show collections  //查看数据库中集合

//在MongoDB中,不需要创建集合。当插入一些文件 MongoDB 自动创建的集合。
>db.user.insert({"name":"tutorials point"})  //插入一条数据
>show collections
movie
user

>db.user.drop()  //删除集合

>db.user.find()  //返回整个集合中的数据

>db.user.find({key1:value1, key2:value2}).pretty()  //集合数据查找,pretty是美化返回结果的格式

>db.user.find("likes": {$gt:10}, $or: [{"by": "yiibai"}, {"title": "MongoDB Overview"}] }).pretty()  //likes, $or

>db.user.find({},{"title":1,_id:0}).limit(2)  //限制条数

>db.mycol.find({},{"title":1,_id:0}).sort({"title":-1})  //sort 1是升序,-1是降序

>db.user.update({'title':'MongoDB Overview'},{$set:{'title':'New MongoDB Tutorial'}})  //更新find的第一条数据

>db.user.update({'title':'MongoDB Overview'},{$set:{'title':'New MongoDB Tutorial'}},{multi:true})  //multi:true 更换所有查到的结果数据

>db.user.save({"_id" : ObjectId(5983548781331adf45ec7), "title":"Yiibai New Topic", "by":"Yiibai"})  //替换该_id的全部数据

>db.user.remove({'title':'MongoDB Overview'})  //删除find的该数据

>db.user.remove()  //清空该集合的所有数据

> db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])    //聚合
{
   "result" : [
      {
         "_id" : "yiibai point",
         "num_tutorial" : 2
      },
      {
         "_id" : "yiibai point",
         "num_tutorial" : 1
      }
   ],
   "ok" : 1
}

详细可查看MongoDB官网DOC

August 12, 2014
Read More

HTTP相应头和请求头对照表

HTTP请求头提供了关于请求,响应或者其他的发送实体的信息。HTTP的头信息包括通用头、请求头、响应头和实体头四个部分。每个头域由一个域名,冒号(:)和域值三部分组成。

August 11, 2014
Read More

DNS Prefetch

DNS 实现域名到IP的映射。通过域名访问站点,每次请求都要做DNS解析。目前每次DNS解析,通常在200ms以下。针对DNS解析耗时问题,一些浏览器通过DNS Prefetch 来提高访问的流畅性。

什么是 DNS Prefetch ?

DNS Prefetch 是一种DNS 预解析技术,当你浏览网页时,浏览器会在加载网页时对网页中的域名进行解析缓存,这样在你单击当前网页中的连接时就无需进行DNS的解析,减少用户等待时间,提高用户体验。

浏览器支持情况

目前支持 DNS Prefetch 的浏览器有 google chrome 和 firefox 3.5

使用方法

如果要浏览器端对特定的域名进行解析,可以再页面中添加link标签实现。例如:

<link rel="dns-prefetch" href="www.ytuwlg.iteye.com" />  

如果要控制浏览器端是否对域名进行预解析,可以通过Http header 的x-dns-prefetch-control 属性进行控制。

google chrome 中 DNS Prefetch 详细资料

在chrome 中可通过在地址栏中输入 about:histograms/DNS.PrefetchFoundName 和 about:dns 来查看当前浏览器的预解析数据。

August 10, 2014
Read More

mongoDB命令

进入mongo安装bin目录
命令输入mongo进行启动
use ueapi 进行切换数据库
show dbs 显示该数据库中的表
show collections 显示当前数据库中所有集合
db.table进入相应的表作用域下
db.users.find() 显示表中所有数据
db. users.remove({'name':'xumingxiang'}) 删除记录
db.users.remove() 删除表中所有记录
db.users.drop() 删除集合
db.dropDatabase() 删除
db.test.find({id:10}) 返回test数据集ID=10的数据集 db.test.find({id:10}).count() 返回test数据集ID=10的数据总数
db.test.find({id:10}).limit(2) 返回test数据集ID=10的数据集从第二条开始的数据集
db.test.find({id:10}).skip(8) 返回test数据集ID=10的数据集从0到第八条的数据集
db.test.find({id:10}).limit(2).skip(8) 返回test数据集ID=1=的数据集从第二条到第八条的数据
db.test.find({id:10}).sort() 返回test数据集ID=10的排序数据集
db.test.findOne([query]) 返回符合条件的一条数据
db.test.getDB() 返回此数据集所属的数据库名称
db.test.getIndexes() 返回些数据集的索引信息
db.test.group({key:...,initial:...,reduce:...[,cond:...]})
db.test.mapReduce(mayFunction,reduceFunction,)
db.test.remove(query) 在数据集中删除一条数据
db.test.renameCollection(newName) 重命名些数据集名称
db.test.save(obj) 往数据集中插入一条数据
db.test.stats() 返回此数据集的状态
db.test.storageSize() 返回此数据集的存储大小
db.test.totalIndexSize() 返回此数据集的索引文件大小
db.test.totalSize() 返回些数据集的总大小
db.test.update(query,object[,upsert
bool]) 在此数据集中更新一条数据
db.test.validate() 验证此数据集
db.test.getShardVersion() 返回数据集共享版本号

August 1, 2014
Read More

产品输出过程

分析竞争状况

(1)市场报告
(2)行业文章
(3)使用竞争对手的产品(竞品分析)

自身资源与满足用户需求的匹配程度

(1)技术资源(是否有技术储备,需要技术预研)
(2)市场资源(媒体资源,推广渠道,公关资源)
(3)运营资源(团队能否支撑可能发生的用户需求)

该阶段目标

(1)发现创新产品的机会
(2)改进现有产品的机会

文档输出

(1)BRD 商业需求文档
(2)MRD 市场需求文档

该注意事项

大胆设想,小心求证
切勿陷入自己营造的主观主义情绪中

产品的规范定义

(1)产品愿景,团队为之去努力的目标与方向
(2)目标市场
(3)竞争分析(得出的结果,共团队成员参考与理解)
(4)产品功能与详细描述
(5)产品功能的优先级
(6)产品用例(use case,主要用于更方便的人理解你的想法)
(7)性能需求(最大并发数,同时在线人数峰值,峰值系统响应时间等)
(8)其他部门支持需求(市场 运营 技术 销售等)

产品设计

(1)明确产品调性
(2)用户体验设计(交互设计 用户体验设计 用户界面设计 前端开发工程)

输出文档

(1)产品信息架构图
(2)产品原型图
(3)产品需求文档(PRD product requirement document)

与各团队充分有效的沟通,协调资源保证产品按照既定目标正确前进

(1)协作并确保各方按既定目标前进
(2)和研发国通合作,确定产品的基本时间节点
(3)产品开发过程中,与项目经理协作,跟踪产品开发进度
(4)与公司高层及时沟通,汇报产品开发过程中的各种问题,困难,协调
(5)及时与团队通报产品进度,确保信息对等

需求管理

(1)新需求(内部的信息反馈和上级的信息反馈,控制好哪些需求是需要加进来,避免产品冻结)
(2)变更需求

产品测试并验收完成

July 13, 2014
Read More

设计层次考虑

UI设计稿中需要体现的信息

  1. 告诉用户这里有他们需要的东西
  2. 帮助用户快速找到他们想要的东西
  3. 适当的时候提供用户可能需要的东西

UI设计中怎么帮助用户快速找到他们想要的东西

  1. 明确页面主题及目标(目标层面)
  2. 设计定位,素材收集,设计层次分析(设计层面)
  3. 交互区重点设计突显(交互层面)
  4. 动效及反馈设置(情感层面)
July 10, 2014
Read More

JQuery源码解析

链式书写

通过方法内return this,返回当前实例就可以

aQuery().init().name()

//实现
aQuery.prototype = {
    init: function() {
        return this;
    },
    name: function() {
        return this
    }
}

插件接口

$.extend是对jquery对象进行扩展,$.fn.extend是对jquery.fn对象进行扩展

$.fn与$.prototype指向同一对象,$.fn.extend相当于扩展prototype上面的方法,当别的类继承jquery时,$.fn上扩展的方法会继承过去,$.extend扩展的方法不能继承。

May 27, 2014
Read More

闭包

什么叫闭包

我理解的闭包是方法返回值的再执行,可以操作方法内部的局部数据。应用场景:设计私有方法和变量。

var audio = (function(){
    var audioObj = function(){
        console.log("constructor");
    };

    audioObj.prototype = {
        start: function(){
            //...
        }
    };

    return audioObj;
})();

var a = new audio();   //console constructor 类的实例
May 26, 2014
Read More

IE textarea focus 兼容问题

问题

IE下面textarea使用.focu()方法,不能聚焦

解决方法

$(this).select(); //体验不好,会把textarea内容选中
$(this).attr('contentEditable',true);  //只在IE中有效,完美解决
May 8, 2014
Read More

createDocumentFragment创建文档碎片节点

document.createDocumentFragment()的作用是提高性能,避免经常做节点插入操作。

var oFragment = document.createDocumentFragment();
for(var i = 0 ; i < 10; i ++) {
    var p = document.createElement("p");
    var oTxt = document.createTextNode("段落" + i);

    p.appendChild(oTxt);
    oFragment.appendChild(p);
}
document.body.appendChild(oFragment);
January 2, 2014
Read More

jquery与原生javascript

选择元素

// jQuery  
var els = $('.el');  

// 原生方法  
var els = document.querySelectorAll('.el');  

// 函数法  
var $ = function (el) {  
  return document.querySelectorAll(el);  
}  

var els = $('.el');  

创建元素

// jQuery  
var newEl = $('<div/>');  

// 原生方法  
var newEl = document.createElement('div');  

添加事件监听器

// jQuery  
$('.el').on('event', function() {  

});  

// 原生方法  
[].forEach.call(document.querySelectorAll('.el'), function (el) {  
  el.addEventListener('event', function() {  

  }, false);  
});  

设置/获取属性

// jQuery  
$('.el').filter(':first').attr('key', 'value');  
$('.el').filter(':first').attr('key');  

// 原生方法  
document.querySelector('.el').setAttribute('key', 'value');  
document.querySelector('.el').getAttribute('key');  

添加/移除/切换类

// jQuery  
$('.el').addClass('class');  
$('.el').removeClass('class');  
$('.el').toggleClass('class');  

// 原生方法  
document.querySelector('.el').classList.add('class');  
document.querySelector('.el').classList.remove('class');  
document.querySelector('.el').classList.toggle('class');  

附加内容(Append)

// jQuery  
$('.el').append($('<div/>'));  

// 原生方法  
document.querySelector('.el').appendChild(document.createElement('div'));  

>克隆元素 
// jQuery  
var clonedEl = $('.el').clone();  

// 原生方法  
var clonedEl = document.querySelector('.el').cloneNode(true);  

移除元素

// jQuery  
$('.el').remove();  

// 原生方法  
remove('.el');  

function remove(el) {  
  var toRemove = document.querySelector(el);  

  toRemove.parentNode.removeChild(toRemove);  
}  

获取父元素

// jQuery  
$('.el').parent();  

// 原生方法  
document.querySelector('.el').parentNode;  

>上一个/下一个元素 
// jQuery  
$('.el').prev();  
$('.el').next();  

// 原生方法  
document.querySelector('.el').previousElementSibling;  
document.querySelector('.el').nextElementSibling;  

XHR或AJAX

// jQuery  
$.get('url', function (data) {  

});  
$.post('url', {data: data}, function (data) {  

});  

// 原生方法  
// get  
var xhr = new XMLHttpRequest();  

xhr.open('GET', url);  
xhr.onreadystatechange = function (data) {  

}  
xhr.send();  

// post  
var xhr = new XMLHttpRequest()  

xhr.open('POST', url);  
xhr.onreadystatechange = function (data) {  

}  
xhr.send({data: data}); 
September 2, 2013
Read More

arguments.callee

arguments返回方法的参数数组,arguments.callee返回自己方法体

function addTime(date, content){
    console.log(arguments, arguments.callee);
}

addTime("2015-3-10", "时间");
// 打印出 ["2015-3-10", "时间"]           
January 3, 2013
Read More

document.all 在各浏览器中的支持不同

各浏览器中对 document.all 方法的支持不同,使用它获取元素引用可能造成兼容性问题。

浏览器返回值

| 浏览器 | 返回值 | | :-------- | --------:| | IE6 IE7 IE8(Q) | document.all : [object] | | Opera Safari IE8(S) | document.all : [object HTMLColletion] | | Firefox(Q) | document.all : [object HTML document.all.class] | | Firefox(S) | document.all : undefined | | Chrome(S) | document.all : [object HTMLColletion] |

!!document.all返回值

| 浏览器 | 返回值 | | :-------- | --------:| | IE6 IE7 IE8 | !!document.all : true | | Firefox Chrome Safari Opera | !!document.all : false |

如下代码firefox(s)报错,document.all undefinded

<html id="HTML1">
<script type="text/javascript">
    window.onload = function() {
        var html = "<table border='1' style='font-size:12px;'>";
        function getElement(sec) {
            html += "<tr><td>" + sec + "</td>" + "<td>" + eval(sec).id + "</td>";
        }
        getElement("document.all(0)");
        getElement("document.all[0]");
        getElement("document.all.item(0)");
        getElement("document.all('SPAN1')");
        getElement("document.all.SPAN1");
        getElement("document.all['SPAN1']");
        getElement("document.all.namedItem('SPAN1')");
        html += "</table>";
        document.getElementById("info").innerHTML = html;
    }
</script>
<span id="SPAN1"></span>
<div id="info"></div>
</html>

解决方法

由于firefox对docuemnt.all支持有问题,所以最好使用document.getElementById, document.getElementByTagName 获取dom

January 2, 2013
Read More