GithubHelp home page GithubHelp logo

blog's People

Contributors

fredshare avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

blog's Issues

test

//热力图上报
(function(){
    //确定url_id
    var hash = location.hash,urlId = 10001;
    function initHash(){
        var hash = location.hash;
        if(hash == "#"){
            urlId = 10001;
        }else if(hash == "#hash1"){
            urlId = 10002;
        }else {
            urlId = 10001;
        }
    }
    initHash();  
    window.addEventListener("hashchange",function(){
        initHash();
        loadHeatmapJsBack();
    });
    //动态载入热力图js
    var s = document.createElement("script");
    s.src = "http://res.wx.qq.com/mmbizwap/en_US/htmledition/js/report/heatmapReport.js";//热力图js的cdn路径;
    s.onload =loadHeatmapJsBack;
    document.getElementsByTagName("head")[0].appendChild(s);
    //载入热力图js后回调
    function loadHeatmapJsBack(){
        if(window.HeatmapReport){
            HeatmapReport.init({
                url_id:urlId,
                radius:4//收归半径4*4
            });
        }
    }
})();

PHP性能监控--xhprof安装

PHP性能检测扩展—xhprof安装

XHProf是facebook开源出来的一个php轻量级的性能分析工具,跟Xdebug类似,但性能开销更低,还可以用在生产环境中,也可以由程序开关来控制是否进行profile。

以下是我在虚拟机上安装的过程记录:

  • 安装lampp

在虚拟机上安装lampp,必须是develop版本的。否则编译是通不过的。我就是因为编译时遇到 include php.h 时就失败了。所以需要先确保下载并安装了 xampp 的 devel packages。下载地址请点击,然后解压到安装的目录tar -xvzf file -C /opt。下载 xampp 的 develop包的时候,注意要选择和自己当前的版本一致的 devel 包,因为 php 的扩展编译的时候,会附加版本信息,启动时进行检查,如果不一致,即便能够编译成功,也是不能够使用的。

  • 安装xhprof
wget http://pecl.php.net/get/xhprof-0.9.2.tgz
tar zxvf xhprof-0.9.2.tgz
cd xhprof-0.9.2
cp -r xhprof_htmlxhprof_lib /opt/lamp/htdocs #应用程序所在目录,其中xhprof_lib是生成统计数据用到的类库。xhprof_html是查看统计数据的时候,用到的类库。
cd extension
/opt/lampp/bin/phpize
./configure
make
make install

编译xhprof的时候出了很多问题,比如:
案例
这个问题是需要安装 此插件。可查看解决。

  • 修改php.ini配置
[xhprof] 
extension=xhprof.so 
xhprof.output_dir=/home/sharexie/xhprof  //如果不加存放目录的话,默认是放在/tmp下面

重启lampp:

/opt/lamp/lamp restart
  • 安装graphviz
cd /usr/src
wget http://www.graphviz.org/pub/graphviz/stable/SOURCES/graphviz-2.24.0.tar.gz
tarzxf graphviz-2.24.0.tar.gz
cd graphviz-2.24.0
./configure&&make && make install
  • 安装libpng

上面的那个工具依赖libpng。到libpng官网down分源码,再次编译一下。
SF.NET上的地址,我下的是这个地址

  • 安装zlib
  • 查看效果

测试代码:

<?php
    index();
    function index(){
        phpinfo();
        b();
    }
    function b(){
        echo "i love you";
    }
    //启动xhprof
    xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
    //停止xhprof
    $xhprof_data = xhprof_disable();
    //取得统计数据
    print_r($xhprof_data);
    $XHPROF_ROOT = realpath(dirname(__FILE__) . '/');
    echo $XHPROF_ROOT;
    include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php";
    include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php";
    include_once $XHPROF_ROOT . "/xhprof_lib/utils/callgraph_utils.php";
    //保存统计数据,生成统计ID和source名称
    $xhprof_runs = new XHProfRuns_Default();
    print_r($xhprof_runs);
    $run_id = $xhprof_runs->save_run($xhprof_data, "test"); //source名称是xhprof_foo
    //弹出一个统计窗口,查看统计信息
    echo "<script language='javascript'>window.open('../xhprof_html/index.php?run=" . $run_id . "&source=test');</script>";
?>

效果如下:

createJS学习之AlphaMaskFilter 类

createJS之EaselJS教程之2--AlphaMaskFilter 类

此类适用于目标对象的图片蒙板的透明度编辑,分离出蒙板的透明管道,复制颜色管道。比如,这能用在更改一个目标的透明蒙板,也能够通过一个压缩过的rgb图片和一个png32的透明蒙板合成一个jpg图片,相比一个单纯的包含argb值的png32格式图片,这能明显的减少图片大小。

重要提示:这个过滤器类暂时还不能正确的支持targetCtx,targetX/Y 参数。

举例

这个例子创建了一个渐变的容器,然后将它用cacheCanvas缓存透明蒙板为一个100*100的图片。

function init() {  
    window.img = new Image();
    img.src = "http://imgtest-lx.meilishuo.net/pic/r/72/31/ee3a366cf629d2ee840831352a29_600_600.jpeg";             
    img.onload = function(){
        drawBitmap();
    }
}
function drawBitmap(){
    var stage = new createjs.Stage("demoCanvas");   
    var box = new createjs.Shape();
    box.graphics.beginLinearGradientFill(["#000000", "rgba(0, 0, 0, 0)"], [0, 1], 0, 0, 200, 200);
    box.graphics.drawRect(0, 0, 200, 200);
    box.cache(0, 0, 200, 200);

    var bitmap = new createjs.Bitmap(img);
    bitmap.filters = [
        new createjs.AlphaMaskFilter(box.cacheCanvas)
    ];
    bitmap.cache(0, 0, 200, 200);
    stage.addChild(bitmap);
    bitmap.x = 0;
    bitmap.y = 0;            
    stage.update();

    bitmap.onClick = function(event) {
        bitmap.rotation = 35;
        bitmap.alpha = 0.5;
        stage.update(); 
    }
} 

Javascript创建对象的几种模式

一、原始模式

原始模式主要是两种,对象字面量和Object构造。如下

var a = {
    name : 'share',
    age : 19,
    method : function(){console.log(this.name)}
}
var a = new Object();
a.name = 'share';
a.age = 19;
a.method = function(){console.log(this.name)}

原始模式有一个问题,如果要批量生成多个a1、a2,就得不断重复copy代码了,所以有了下面的方法,工厂模式、构造器模式、圣杯模式等。

二、工厂模式

function parent(name){
    var child = {};
    child.name = name;
    child.method = function(){
        console.log(this.name);
    };   
    return child;
}
var childA = parent('lily');
var childB = parent('lucy');
childA.method(); //lily
childB.method(); //lucy
console.log(childA.method === childB.method) //false

工厂模式就是批量化生产,简单调用就可以进入造人模式。
由于是工厂暗箱操作的,所以你不能识别这个对象到底是什么类型。
经典工厂模式是直接执行parent()方法,而不是通过new的方式。混合工厂模式尽量不用。
工厂模式中每生成一个子类,就会重复生成相应的方法,代码臃肿。

三、构造函数模式

function Parent(name){
    this.name = name;
    this.method = function(){
        console.log(this.name);
    }
}
var childA = new Parent('lily');
var childB = new Parent('lucy');
childA.method(); //lily
childB.method(); //lucy
console.log(childA.method === childB.method) //false

构造器模式,用new的方式构造子类。同时构造器函数首字母大写。
如果直接执行Parent(),那么属性方法都赋值给window对象了。

四、原型模式

function Parent(){}
Parent.prototype.name = 'share';
Parent.prototype.method = function(){console.log(this.name)};
var childA = new Parent();
var childB = new Parent();
console.log(childA.name === childB.name); //true
console.log(childA.method === childB.method); //true

或者

function Parent(){}
Parent.prototype = {
    name : 'share',
    method : function(){console.log(this.name)}
};
var childA = new Parent();
var childB = new Parent();
console.log(childA.name === childB.name); //true
console.log(childA.method === childB.method); //true

原型属性和方法的共享,即所有实例中都只是引用原型中的属性方法,任何一个地方产生的改动会引起其他实例的变化。

五、构造器和原型的混合模式

function Parent(name){
    this.name = name;
}
Parent.prototype = {
    method : function(){
        console.log(this.name);
    }
}
var childA = new Parent('lily');
var childB = new Parent('lucy');
console.log(childA.name === childB.name); //false
console.log(childA.method === childB.method); //true

将构造器和原型模式的优点结合起来了。
需要独立的属性方法放入构造函数中,而可以共享的部分则放入原型中,这样做可以最大限度节省内存而又保留对象实例的独立性。

六、Object.create()方法

Object.create()可以接收两个参数:提供原型的对象,可选属性对象(这个对象包含对新创建对象的配置)。

var Car = {
    drive: function (miles) {
        return this.odometer += miles;
    }
};
var tesla = Object.create(Car, {
    'odometer': {
        value: 0,
        enumerable: true
     }     
));
console.log(tesla.drive(10));//10

为什么回不去二线城市

今天一朋友对我说得很好,为什么回不去成都了?
在一线城市就现在的我来说,就缺钱,但是钱可以慢慢赚,但是在二线城市可能现阶段能有点钱,但是其他什么都没有,生活环境,便利性,机会,成就感,自由与相对的公平,二三线城市很多时候是靠关系的。

php打造可视化源码发布系统

php打造可视化源码发布系统

  • 前言

    之前在大公司里有现成文件发布系统。今年在创业公司,很多工具都得自己从头搭建,比如日志、itil监控、用户信息监控。这次是源码发布系统。在最开始我们直接使用ftp上传到idc机器,因为idc机器只有一台,用ftp很简单;随着业务不断扩大,idc机器越来越多,ftp发布就变得很麻烦了,你得一个文件一个文件上传不说,还得切换机器上传。我们研究了常见的文件同步软件后,采用了rsync软件同步。 rsync很方便的就是可以一次同步到多个机器,可以备份,方便回退;唯一的缺点就是命令行操作,不能查看以往的发布记录。所以当团队越来越大的时候很有必要基于sync做一个可视化的发布系统。

  • 需要解决的问题点

    • 文件目录可视化操作勾选以及搜索
    • 以发布任务的形式操作文件发布、回退
    • 源代码查看以及和线上代码对比功能
  • 一个一个解决

    • 目录文件可视化操作

    随便百度了下,发现有很多这样的开源项目,采用了jstree项目,这个项目对服务器上的路径的目录文件能很好的解析,同时配备js代码绘制树形结构,很方便就画好文档树了。如下图

image

* 任务发布

当点击文件的时候,将文件展示出来,并添加查看源码和文件对比的功能。
$('#tree')
    .jstree({
        'core' : {
            'data' : {
                'url' : '/release/getNodeInfo?path='+path+'&operation=get_node',
                'data' : function (node) {
                    return { 'id' : node.id };
                }
            },
            'check_callback' : function(o, n, p, i, m) {
                if(m && m.dnd && m.pos !== 'i') { return false; }
                if(o === "move_node" || o === "copy_node") {
                    if(this.get_node(n).parent === this.get_node(p).id) { return false; }
                }
                return true;
            },
            'themes' : {
                'responsive' : false,
                'variant' : 'small',
                'stripes' : true
            }
        },
        'sort' : function(a, b) {
            return this.get_type(a) === this.get_type(b) ? (this.get_text(a) > this.get_text(b) ? 1 : -1) : (this.get_type(a) >= this.get_type(b) ? 1 : -1);
        },
        'contextmenu' : {
            'items' : function(node) {
                var tmp = $.jstree.defaults.contextmenu.items();
                delete tmp.create.action;
                tmp.create.label = "New";
                tmp.create.submenu = {
                    "create_folder" : {
                        "separator_after"   : true,
                        "label"             : "Folder",
                        "action"            : function (data) {
                            var inst = $.jstree.reference(data.reference),
                                obj = inst.get_node(data.reference);
                            inst.create_node(obj, { type : "default" }, "last", function (new_node) {
                                setTimeout(function () { inst.edit(new_node); },0);
                            });
                        }
                    },
                    "create_file" : {
                        "label"             : "File",
                        "action"            : function (data) {
                            var inst = $.jstree.reference(data.reference),
                                obj = inst.get_node(data.reference);
                            inst.create_node(obj, { type : "file" }, "last", function (new_node) {
                                setTimeout(function () { inst.edit(new_node); },0);
                            });
                        }
                    }
                };
                if(this.get_type(node) === "file") {
                    delete tmp.create;
                }
                return tmp;
            }
        },
        'types' : {
            'default' : { 'icon' : 'folder' },
            'file' : { 'valid_children' : [], 'icon' : 'file' }
        },
        'unique' : {
            'duplicate' : function (name, counter) {
                return name + ' ' + counter;
            }
        },
        'plugins' : ['state','dnd','sort','types','contextmenu','unique']
    })
    .on('delete_node.jstree', function (e, data) {
        $.get('/release/getNodeInfo?path='+path+'&operation=delete_node', { 'id' : data.node.id })
            .fail(function () {
                data.instance.refresh();
            });
    })
    .on('create_node.jstree', function (e, data) {
        $.get('/release/getNodeInfo?path='+path+'&operation=create_node', { 'type' : data.node.type, 'id' : data.node.parent, 'text' : data.node.text })
            .done(function (d) {
                data.instance.set_id(data.node, d.id);
            })
            .fail(function () {
                data.instance.refresh();
            });
    })
    .on('rename_node.jstree', function (e, data) {
        $.get('/release/getNodeInfo?path='+path+'&operation=rename_node', { 'id' : data.node.id, 'text' : data.text })
            .done(function (d) {
                data.instance.set_id(data.node, d.id);
            })
            .fail(function () {
                data.instance.refresh();
            });
    })
    .on('move_node.jstree', function (e, data) {
        $.get('/release/getNodeInfo?path='+path+'&operation=move_node', { 'id' : data.node.id, 'parent' : data.parent })
            .done(function (d) {
                //data.instance.load_node(data.parent);
                data.instance.refresh();
            })
            .fail(function () {
                data.instance.refresh();
            });
    })
    .on('copy_node.jstree', function (e, data) {
        $.get('/release/getNodeInfo?path='+path+'&operation=copy_node', { 'id' : data.original.id, 'parent' : data.parent })
            .done(function (d) {
                //data.instance.load_node(data.parent);
                data.instance.refresh();
            })
            .fail(function () {
                data.instance.refresh();
            });
    })
    .on('changed.jstree', function (e, data) {
        if(data && data.selected && data.selected.length) {
            var id = data.selected.join(':');
            if(id.split('.').length>1){
                //保存id信息
                if(!isIdExist(id)){
                    saveId(id);
                    $('#js_file_list').append('<li class="jstree-node  jstree-no"><span class="js_path">'+ id +'</span>&nbsp;&nbsp;<a href="#del" class="js_del">删除</a>&nbsp;&nbsp;<a href="#query" class="js_query">查看文件</a>&nbsp;&nbsp;<a href="#query" class="js_diff">对比文件</a></li>');
                }
            }



        }
        else {
            //$('#data .content').hide();
            $('#data .default').html('Select a file from the tree.').show();
        }
    });
    function isIdExist(id){
        for (var i = 0; i < fileList.length; i++) {
            if(fileList[i] == id){
                return true;
            }
        };
        return false;
    }
    function saveId(id){
        fileList.push(id);
    }
    function delId(id){
        for (var i = 0; i < fileList.length; i++) {
            if(fileList[i] == id){
                fileList.splice(i,1)
            }
        };
    }
    $('body').delegate('.js_del','click',function(e){
        var target = $(e.target).closest('li'),
            id = target.find('.js_path').text();
        console.log(target);
        target.remove();
        delId(id);
    })
    $('body').delegate('.js_query','click',function(e){
        var target = $(e.target).closest('li'),
            id = target.find('.js_path').text();
        var loading_id = layer.load(2);
        $.get('/release/getNodeInfo?path='+path+'&operation=get_content&id=' + id, function (d) {
            if(d && typeof d.type !== 'undefined') {
                switch(d.type) {
                    case 'text':
                    case 'txt':
                    case 'md':
                    case 'htaccess':
                    case 'log':
                    case 'sql':
                    case 'php':
                    case 'js':
                    case 'json':
                    case 'css':
                    case 'html':
                        //$('#data .code').show();
                        //$('#code').val(d.content);
                        //break;
                    case 'png':
                    case 'jpg':
                    case 'jpeg':
                    case 'bmp':
                    case 'gif':
                        /*$('#data .image img').one('load', function () { $(this).css({'marginTop':'-' + $(this).height()/2 + 'px','marginLeft':'-' + $(this).width()/2 + 'px'}); }).attr('src',d.content);
                        $('#data .image').show();*/
                        layer.close(loading_id);
                        layer.open({
                            type: 2,
                            title: false,
                            closeBtn: 0, //不显示关闭按钮
                            shade: [0],
                            area: ['340px', '215px'],
                            offset: 'rb', //右下角弹出
                            time: 1000, //1秒后自动关闭
                            shift: 2,
                            content: ['/release/fileInfo?path='+path+'&operation=get_content&id='+id, 'no'], //iframe的url,no代表不显示滚动条
                            end: function(){ //此处用于演示
                                layer.open({
                                    type: 2,
                                    title: '源码查看-'+id,
                                    shadeClose: true,
                                    shade: false,
                                    maxmin: true, //开启最大化最小化按钮
                                    area: ['893px', '600px'],
                                    content: '/release/fileInfo?path='+path+'&operation=get_content&id='+id
                                });
                            }
                        }); 
                        break;
                    default:
                        //$('#data .default').html(d.content).show();
                        //$('#js_file_list').append('<li class="jstree-node  jstree-no">'+data.selected.join(':')+'&nbsp;&nbsp;<a href="#del">删除</a>&nbsp;&nbsp;<a href="#query">查看文件</a></li>');
                        break;
                }
            }
        });
    })
    $('body').delegate('#js_release','click',function(e){
        console.log(fileList);
    })
    $('body').delegate('.js_diff','click',function(e){
        var target = $(e.target).closest('li'),
            id = target.find('.js_path').text();
        var loading_id = layer.load(2);
        layer.close(loading_id);
        layer.open({
            type: 2,
            title: false,
            closeBtn: 0, //不显示关闭按钮
            shade: [0],
            area: ['340px', '215px'],
            offset: 'rb', //右下角弹出
            time: 1000, //1秒后自动关闭
            shift: 2,
            content: ['/release/diffFile?path='+path+'&id='+id, 'no'], //iframe的url,no代表不显示滚动条
            end: function(){ //此处用于演示
                layer.open({
                    type: 2,
                    title: '源码对比-'+id,
                    shadeClose: true,
                    shade: false,
                    maxmin: true, //开启最大化最小化按钮
                    area: ['893px', '600px'],
                    content: '/release/diffFile?path='+path+'&id='+id
                });
            }
        }); 
    })
});

效果如下图:

image

  • 文件源码查看和问价对比

    文件源码查看比较简单,路径发到后台,后台读出文档内容返回给前端,前端用codemirror渲染下就行了,如下:

image

文件对比就比较麻烦了,你得分别读开发环境下的文件的线上的文件,再一行一行的对比,还得渲染出来,不过网上还蛮多这样的开源项目,拿来主义,哈哈。我采用了[php-diff](https://github.com/chrisboulton/php-diff)项目。效果如下:

image

  • 任务系统这块未完待续

创业一年总结

创业一年半总结

审视产品、团队、市场
创业过程中遇到的坑
关于带团队的理解

  • 审视产品、团队、市场

寻找早中期公司机会时,一般是从产品、团队、市场三个方面来考察这个公司、项目是否可靠可行。三个方面的情况都需要自己亲自勘察。

比如初创团队和创始人。除了单独和他面谈,通过他对这个市场的分析,对产品的规划等了解1、公司业务的情况;2、了解这个人对整个行业的理解;3、分析人物性格,做事风格。同时也需要多从行业人士或者其他人的角度来了解这些初创团队,特别是创始人。因为创始人在初创公司太重要,如果多人做决定,出现妥协的情况就会容易导致没有人来负责;所以一般是必须有一个一锤定音的人,一般就是创始人。如果创始人(或者ceo)对行业了解不深(很多互联网从业者有很好的背景,打着互联网+的名号杀入其他行业),请做好碰多次壁的准备。同时从面谈来分析一个人毕竟有限且容易被误导,从事偏运营的人说话易满,很容易被鼓舞;从事偏技术的人说话很实在,很多人有货说不出来。所以听运营讲话要听一半信一半,听技术出身的人讲可以适当放大一下。

  • 创业过程中遇到的坑
  1. 管理

不太清楚其他公司的情况,反正我们当时公司的情况到中后期,产品负责人调去负责供应链,然后又调去负责各地城市站, 运营。技术负责人负责产品线。下面的人的工作职责也变化很快。当然创业公司业务线不断调整变化我没什么意见,但是人员职责变动太快导致了一个问题:员工没有负责任的心态,同时成就感不强,渐渐的就会失去工作积极性。

  1. 公司扩张

从2015年3月成立时候15个人左右,到A轮9月份融完资80多人,到2016年1月最高140多人。团队扩张速度不可谓不快,但是相应的业务其实没有跟上,我理解天使轮应该是提出方向,组建团队,开始业务模式的时期;A轮应该是模式验证时期;B轮是模式验证清晰,开始业务复制时期;C、D轮开始业务扩展盈利时期。但是我们在A轮的时候就把自己定位成B轮之后了,业务模式还处在验证时期,最多的时候开了北上广深、武汉、西安、成都、重庆八个城市站。每个城市的具体情况不同,自身产品流程有待验证,各城市沟通麻烦。最终的结果就是产品方向还在不断的调整,各城市也跟不上,一个一个裁掉城市站,浪费了大量的人力物力时间成本。

  1. 招人

核心团队人员不可谓不豪华,核心团队都是BAT等各大互联网巨头背景出身的人,大数据,亿万流量,行业分析都是得心应手。但是落到具体执行上面,经常开会结论没有具体方案,结论是大家好好干,技术做好技术,运营用心服务用户。其实创业公司很多底层员工经验不够丰富,这样的结论让大家很懵逼。作为老大,leader不仅需要定好方向,同时需要定好执行的步骤,要下面的员工按照分解的工作,定好deadline一步一步的做。
那我们公司之前的例子:
市场总监招过4个,两个贪污,一个无所事事,一个异地办公,沟通麻烦。
hr总监之前和公司闹掰了,赔了不少钱。

  1. 烧钱模式

天使轮500万,A轮3000万,一年半全部用完,主要花在了市场推广方面。一次市场补贴几百万,朋友圈广告100万,mp广告100万,各种地推,各种营销补贴。
这个还是我上面说的,应该是在B轮后,产品模式验证清晰了之后才应该有的动作,没验证清晰之前盲目扩张,补贴的时候看着数据噌噌噌的往上涨,很开心呀, 结果一没补贴,数据全掉了。因为没有达到用户痛点,用户是来领补贴的,没有补贴当然就流失了。
其实创业过程中,现金流真的很重要,有钱可以让你撑到最后,即使到那个时候还没有盈利,谁撑到了最后谁就是赢家。例子太多了,我们楼上有一家公司,A轮的钱到账了一分钱没用存到银行,我们天使轮、A轮的前都快花完的时候,楼上融了B轮,A轮的钱还没动。至少说明了,真正找到用户的痛点得产品是不需要花那么多冤枉钱的。通过广告的方式烧钱只能得到一时的繁荣,后面都是在裸泳。

  • 关于带团队的理解

我理解的带团队,一是把自己高效的工作方式流程化、标准化,让团队的工作效率都要得到提成,让团队的战斗力大大增强;二是解决团队中每个人员的难处,包括工作难题、生活问题、待遇,只有你真正关心大家,大家才会死心塌地的干活,团队才有凝聚力;三事信息的传递上,作为一个中间干部,需要对上下级做合适的信息传递。上面传达的压力需要分解成有计划有步骤的工作安排,下面的功劳需要向上面及时反应,让团队都知道;有一点非常重要,如果团队中有人出了问题,leader一定不要让他站出来,二是首先自己扛下来。

利用gulp打造前端集成开发环境一--介绍篇

gulp介绍

  • gulp是基于流的构建工具,把源文件倒入一个处理容器1(任务1),再倒入处理容器2(任务2)。。。最后倒入最终的容器(目标文件)
  • 和grunt类似,不过grunt的io操作太频繁

    gulp安装

  • 安装nodejs
  • 安装gulp
     npm install -g gulp
     npm install --save-dev gulp

gulp的使用

 gulp的任务都是以插件的形式存在,以安装gulp-jshint为例
  • 安装gulp-jshint
     npm install gulp-jshint --save-dev
  • 创建gulpfile.js
var gulp = require('gulp');
var jshint = require('gulp-jshint');
var paths = {
  scripts: 'js/**/*.js',
};
gulp.task('lint', function() {
  return gulp.src(paths.scripts)
    .pipe(jshint())
    .pipe(jshint.reporter('default'));
});
  • 执行
        gulp lint

其实安装gulp和gulp的插件都是使用node在本地进行安装的,会自动生成相应的目录。最主要的还是这个gulpfile.js。就相当于main函数,当执行gulp的时候,就会主动地去gulpfile.js中去执行相应的任务。

什么是src和pipe?

先看一个unix命令:cat gulpfile.js | wc -l
这是两个独立的命令,cat guplfile.js 表示获取gulpfile.js的内容,wc -l表示统计文件中的行数,中间用|分隔,表示前面命令的输出作为后面命令的输入。src就是获取源文件,pipe就是管道操作。

5个最常见的命令:

gulp.task(name, fn)定义一个任务
gulp.run(tasks...)尽可能多的并行运行多个task
gulp.watch(glob, fn)当glob内容发生改变时,执行fn
gulp.src(glob)返回一个可读的stream
gulp.dest(glob)返回一个可写的stream

查看各个gulp插件的官网:https://www.npmjs.org/

前端集成开发环境

好了,介绍完了,gulp,我们来说说集成开发环境是什么?
我个人是在看了张云龙的博客之后才对前端工程、前端集成开发环境有了一定的了解的。那么我所理解的前端集成开发环境是指 一套解决js自身三大缺陷的通用解决方案。前端语言有哪三大缺陷:

资源定位:获取任何开发中所使用资源的线上路径;
内容嵌入:把一个文件的内容(文本)或者base64编码(图片)嵌入到另一个文件中;
依赖声明:在一个文本文件内标记对其他资源的依赖关系;

前端集成开发环境的目标是:

代码部署
文件压缩
文件合并
文件加MD5戳
前端模块化开发
组合插件
css sprite
less开发
内容嵌入
支持less编译css
支持react

我的项目最终的gulpfile如下

var gulp = require('gulp'),
    uglify = require('gulp-uglify'),
    md5 = require('gulp-md5-plus'),
    seajs = require('gulp-seajs'),
    replace = require('gulp-replace'),
    minifyCss = require('gulp-minify-css'),
    less = require('gulp-less'),
    cli = require('./cli.js'),  
    htmlmin = require('gulp-htmlmin'),
    jshint = require('gulp-jshint'),
    imagemin = require('gulp-imagemin'),
    pngquant = require('imagemin-pngquant'),
    cache = require('gulp-cache'),
    react = require('gulp-react'),
    newDep = require('gulp-dep');


//变量设置
var jsPath = {
    src : '../static/src/scripts',
    release : '../static/release/scripts'
},cssPath = {
    src : '../static/src/styles',
    release : '../static/release/styles'
},htmlPath = {
    src : '../application/views',
    release : '../application/views/'
},imgPath = {
    src : '../static/src/images',
    release : '../static/release/images/'
};

//默认执行方法
gulp.task('default',["main"],function(){

});


process.on('uncaughtException', function(err) {
    console.log(err);
})

//html处理,处理<!--script-->等标签
gulp.task('htmldep',function(){
    gulp.src(htmlPath.src + '/**/*.php')
        .pipe(newDep())
        .pipe(gulp.dest(htmlPath.release));
})
//html压缩
gulp.task('htmlmin',function(){
    gulp.src([htmlPath.src + '/m3/channel/index.php',"!" + htmlPath.src + 'apiview.php'])
        .pipe(htmlmin({collapseWhitespace: true}))
        .pipe(gulp.dest(htmlPath.release + '/m3/channel/'));
})
//移动lib任务
gulp.task('libmove',function(){
    //移动lib第三方库  不压缩
    gulp.src(jsPath.src + '/library/**/*.js')
        .pipe(gulp.dest(jsPath.release + '/library/'));
})
//移动common、mobile、www业务库,seajs处理、压缩
gulp.task('jsmin',function(){
    gulp.src([jsPath.src + '/**/*.js', "!" + jsPath.src + "/library/**/*.js"])
        .pipe(seajs())
        .pipe(uglify({
            mangle:true
        }))
        .pipe(gulp.dest(jsPath.release));
})
//css压缩、移动
gulp.task('cssmin',function(){
    gulp.src(cssPath.src + '/**/*.css')
        //.pipe(less()) //less编译
        .pipe(minifyCss({compatibility: 'ie8'}))
        .pipe(gulp.dest(cssPath.release));
})
//css的less编译
gulp.task('less',function(){
    gulp.src(cssPath.src + '/**/*.less')
        .pipe(less()) //less编译
        .pipe(minifyCss({compatibility: 'ie8'}))
        .pipe(gulp.dest(cssPath.release));
})
//图片压缩
gulp.task('imgmin',function(){
    gulp.src(imgPath.src + '/**/*.{png,jpg,gif,ico}')
        .pipe(cache(imagemin({
            optimizationLevel: 5,
            progressive: true, //类型:Boolean 默认:false 无损压缩jpg图片
            interlaced: true, //类型:Boolean 默认:false 隔行扫描gif进行渲染
            multipass: true //类型:Boolean 默认:false 多次优化svg直到完全优化
        })))
        .pipe(gulp.dest(imgPath.release));
});

//react 
gulp.task('react-dev',['htmldep'],function(){
    gulp.src(jsPath.src + '/**/react-test.js')
        .pipe(react())
        .pipe(gulp.dest(jsPath.release))
})
//react 
gulp.task('react-idc',['htmldep'],function(){
    gulp.src(jsPath.src + '/**/react-test.js')
        .pipe(react())
        .pipe(uglify({
            mangle:true
        }))
        .pipe(gulp.dest(jsPath.release))
})
//react
gulp.task('main',['htmldep','libmove','jsmin','cssmin','less'],function() {

});

//监听任务
gulp.task('watch', function() { 
    gulp.watch([jsPath.src + '/**/*.js', "!" + jsPath.src + "/library/**/*.js"]).on('change', function(event) {
        /*var dir = event.path.match(/\/src\/(styles|scripts)(.*)\/.*\.(css|js)$/)[2];
        console.log(event.path);
        console.log(dir);
        gulp.src(event.path)
            .pipe(seajs())
            .pipe(gulp.dest(jsPath.release + dir));*/
        console.log('files changed');
        gulp.src([jsPath.src + '/**/*.js', "!" + jsPath.src + "/library/**/*.js"])
            .pipe(seajs())
            .pipe(gulp.dest(jsPath.release));
    });
});

1

11

CentOS6.5安装gitlab

GitLab,是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。

它拥有与Github类似的功能,能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库。团队成员可以利用内置的简单聊天程序(Wall)进行交流。它还提供一个代码片段收集功能可以轻松实现代码复用,便于日后有需要的时候进行查找。

开源项目地址:https://github.com/gitlabhq/gitlabhq

Distribution : CentOS 6.5 Minimal

GitLab version : 7.4.5

GitLab-shell : 2.0.1

Ruby version : ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]

Gem version : 2.2.2

Redis-server : Redis server version 2.4.10 (00000000:0)

Web Server : Nginx/1.0.15

Database : MySQL/5.5.40

一,安装源和依赖包
cd /usr/local/src
#增epel源,如果你是i686系统,请把x86_64修改下。
wget -O /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6 https://www.fedoraproject.org/static/0608B895.txt
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

#确认是否安装成功
rpm -qa gpg*
gpg-pubkey-0608b895-4bd22942

#增puias源
wget -O /etc/yum.repos.d/PUIAS_6_computational.repo https://gitlab.com/gitlab-org/gitlab-recipes/raw/master/install/centos/PUIAS_6_computational.repo
wget -O /etc/pki/rpm-gpg/RPM-GPG-KEY-puias http://springdale.math.ias.edu/data/puias/6/x86_64/os/RPM-GPG-KEY-puias
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-puias

#验证是否成功
rpm -qa gpg*
gpg-pubkey-41a40948-4ce19266

查看仓库源
yum repolist
已加载插件:fastestmirror
Loading mirror speeds from cached hostfile

  • PUIAS_6_computational: www.puias.princeton.edu
  • epel: ftp.sjtu.edu.cn
    仓库标识 仓库名称 状态
    PUIAS_6_computational PUIAS computational Base 6 - x86_64 2,638
    base CentOS-6 - Base - 163.com 6,518
    *epel Extra Packages for Enterprise Linux 6 - x86_64 11,148
    extras CentOS-6 - Extras - 163.com 36
    updates CentOS-6 - Updates - 163.com 727
    repolist: 21,067

如果此列表中没有epel和PUIAS_6_computational,请执行以下命令

yum-config-manager --enable epel --enable PUIAS_6_computational

二,安装依赖包
yum -y update
yum -y groupinstall 'Development Tools'
yum -y install readline readline-devel ncurses-devel gdbm-devel glibc-devel tcl-devel openssl-devel curl-devel expat-devel db4-devel byacc sqlite-devel libyaml libyaml-devel libffi libffi-devel libxml2 libxml2-devel libxslt libxslt-devel libicu libicu-devel system-config-firewall-tui redis sudo wget crontabs logwatch logrotate perl-Time-HiRes git cmake libcom_err-devel.i686 libcom_err-devel.x86_64

安装邮件服务

postfix或者sendmail,官网上安装是postfix,本人默认就装来sendmial,所以此步骤省略

三,安装git

默认centos的git版本是1.7.10,所以要先删除,然后再下载源码安装
yum remove git -y

yum install zlib-devel perl-CPAN gettext curl-devel expat-devel gettext-devel openssl-devel

mkdir /tmp/git && cd /tmp/git

curl --progress https://www.kernel.org/pub/software/scm/git/git-2.1.3.tar.gz | tar xz

cd git-2.1.3/ && ./configure && make && make prefix=/usr/local install

完成后验证
which git
/usr/local/bin/git

git --version
git version 2.1.3

四,安装ruby

ruby版本需要2.0+,所以先卸载系统已存在的
yum remove ruby
#如果是源码安装的
cd (your-ruby-source-path) && make uninstall

mkdir /tmp/ruby && cd /tmp/ruby

curl --progress ang.org/pub/ruby/2.1/ruby-2.1.2.tar.gz | tar xz

cd ruby-2.1.2 && ./configure --disable-install-rdoc && make && make prefix=/usr/local install

安装bundler

gem install bundler --no-doc

完成后验证
which ruby
/usr/local/bin/ruby

ruby -v
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]

五,创建系统用户

adduser --system --shell /bin/bash --comment 'GitLab' --create-home --home-dir /home/git/ git

增加/usr/local/bin
visudo
#修改以下内容
Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

六,安装mysql

官网给出两个选择,mysql、postgreSQL,我使用的mysql

centos默认会安装5.1版本的mysql,所以要源码安装,此步骤掠过。。。
#mysql的版本至少5.5.14或更新
mysql --version
mysql Ver 14.14 Distrib 5.5.40, for Linux (x86_64) using readline 5.1

创建数据库用户并授权
mysql -u root -p

mysql> CREATE USER 'git'@'localhost' IDENTIFIED BY 'gitpwd';

mysql> show variables like "%engine";
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
| storage_engine | InnoDB |
+------------------------+--------+
2 rows in set (0.01 sec)

#如果不是InnoDB引擎,需执行下面命令
mysql> SET storage_engine=INNODB;

创建数据库

mysql> CREATE DATABASE IF NOT EXISTS gitlabhq_production DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

给用户授权

mysql> GRANT SELECT, LOCK TABLES, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON gitlabhq_production.* TO 'git'@'localhost';

测试是否能够成功登录
mysql -ugit -pgitpwd -D gitlabhq_production
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 30
Server version: 5.5.40-log Source distribution

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> \q

七,配置redis
chkconfig redis on

cp /etc/redis.conf /etc/redis.conf.orig

#修改监听端口
sed 's/^port .*/port 0/' /etc/redis.conf.orig |tee /etc/redis.conf

#增加内容
echo 'unixsocket /var/run/redis/redis.sock' |tee -a /etc/redis.conf

echo -e 'unixsocketperm 0770' |tee -a /etc/redis.conf

创建目录改权限
mkdir /var/run/redis

chown redis:redis /var/run/redis

chmod 755 /var/run/redis

启动服务

service redis restart

附加git到redis组

usermod -aG redis git

八,安装gitlab
cd /home/git

#下载源码
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-4-stable gitlab

修改配置
cd gitLab/

sudo -u git -H cp config/gitlab.yml.example config/gitlab.yml

sudo -u git -H vim config/gitlab.yml
gitlab:
## Web server settings (note: host is the FQDN, do not include http://)
host: localhost
port: 80
https: false

修改目录权限
chown -R git log/
chown -R git tmp/
chmod -R u+rwX log/
chmod -R u+rwX tmp/
chmod -R u+rwX tmp/pids/
chmod -R u+rwX tmp/sockets/
chmod -R u+rwX public/uploads

创建目录
sudo -u git -H mkdir /home/git/gitlab-satellites
chmod u+rwx,g=rx,o-rwx /home/git/gitlab-satellites

编辑配置文件unicorn.rb
sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb

#查看系统核心数
nproc
4

#编辑配置
sudo -u git -H vim config/unicorn.rb
worker_processes 4

拷贝配置文件rack_attack.rb

sudo -u git -H cp config/initializers/rack_attack.rb.example config/initializers/rack_attack.rb

定义全局的用户和邮箱
sudo -u git -H git config --global user.name "GitLab"
sudo -u git -H git config --global user.email "[email protected]"
sudo -u git -H git config --global core.autocrlf input

编辑连接redis配置
#拷贝配置
sudo -u git -H cp config/resque.yml.example config/resque.yml

#连接redis配置,默认配置,未修改
sudo -u git -H vim config/resque.yml

九,配置gitlab数据库文件
sudo -u git cp config/database.yml.mysql config/database.yml

#编辑配置文件
sudo -u git -H vim config/database.yml
production:
adapter: mysql2
encoding: utf8
collation: utf8_general_ci
reconnect: false
database: gitlabhq_production
pool: 10
username: git
password: "gitpwd"
host: localhost
socket: /var/lib/mysql/mysql.sock

#修改文件权限,只有git用户可读
sudo -u git -H chmod o-rwx config/database.yml

十,安装gem
cd /home/git/gitLab

sudo -u git -H bundle install --deployment --without development test postgres aws

十一,安装gitlab-shell

官网上给的gitlab-shell版本是2.1.0,后面会有问题(本地到远程不能连接),网上查找问题是版本问题,需要gitlab-shell的版本是2.0.1
sudo -u git -H bundle exec rake gitlab:shell:install[v2.0.1] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production

#编辑配置
sudo -u git -H vim /home/git/gitlab-shell/config.yml

user: git
gitlab_url: https://localhost/
http_settings:
self_signed_cert: true
repos_path: "/home/git/repositories/"
auth_file: "/home/git/.ssh/authorized_keys"
redis:
bin: "/usr/bin/redis-cli"
namespace: resque:gitlab
socket: "/var/run/redis/redis.sock"
log_level: INFO
audit_usernames: false

十二,初始化数据库
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production

#可以设置管理员密码(此步骤可省略。。。)
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production GITLAB_ROOT_PASSWORD=newpassword

十三,下载服务脚本
wget -O /etc/init.d/gitlab https://gitlab.com/gitlab-org/gitlab-recipes/raw/master/init/sysvinit/centos/gitlab-unicorn

chmod +x /etc/init.d/gitlab

chkconfig --add gitlab

chkconfig gitlab on

#设置logrotate
cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab

#检测应用状态
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production

sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production

#启动服务
service gitlab start

十四,配置web服务
#本人使用的nginx
yum -y install nginx

chkconfig nginx on

wget -O /etc/nginx/conf.d/gitlab.conf https://gitlab.com/gitlab-org/gitlab-ce/raw/master/lib/support/nginx/gitlab-ssl

添加nginx用户到git组
usermod -a -G git nginx

chmod g+rx /home/git/

修改配置,修改server_name

vim /etc/nginx/conf.d/gitlab.conf

启动服务
service nginx start

#访问登录
#用户名:root
#密码:5iveL!fe

小小的吐槽

这样写 是比较方便,

没感觉界面很不友好么.

还有分类和tag根本没有额

nginx配置学习篇

nginx配置学习篇

最近需要对网站的nginx进行配置,学习了下相关的知识。
需要解决的问题:

没有www的域名test.com指向到www.test.com
移动端自动指向到m.test.com上,pc上访问自动指向到www.test.com

对于第一个问题:

域名提供商管理页面进行相关配置,新增一个域名解析记录,记录类型为A记录,意思是说当用户输入test,com时候将转到ip为xx.xx.xx.xx的机器

image

设置相关机器的nginx配置,新增一条server记录

一般nginx的配置都在/usr/local/nginx/conf/

server {
    server_name test.com;
    rewrite ^/(.*)$ http://www.test.com/home_page permanent;
    root   html;
    index  index.html index.htm;
}

对于第二个问题:

server {
    server_name test.com;
    if ( $http_user_agent ~* "(Android|webOS|iPhone|iPod|BlackBerry)" ) {
            rewrite ^/(.*)$ http://mobile.test.com/home_page permanent;
    }
    rewrite ^/(.*)$ http://www.test.com/home_page permanent;
    root   html;
    index  index.html index.htm;
}

Linux中session失效的原因之一

Linux中session失效的原因之一是session所在的目录没有权限的问题,开始的时候认为是程序和数据的问题,死活登陆不进去,网上搜遍了找不到问题所在,最后通过调试城市发现时session引起的登陆信息报错,最终想到是session目录的权限问题,加上相应的权限就可以了,还是有点小棘手的,window下面就不存在这种问题,chmod 777 session所在的路径名称

createJs 学习之准备工作

准备工作

我们首先把html文档弄好,然后在里面来体验EaselJS。 一下所有实例,楼主都亲测过。有问题可交流。

<head>  
    <script src="http://code.createjs.com/easeljs-0.7.0.min.js"></script>  
    <script>  
        unction init() {  
            // code here.  
        }  
    </script>  
</head>  
<body onLoad="init();">  
    <canvas id="demoCanvas" width="500" height="300">  
        alternate content  
    </canvas>  
</body>  

PHP性能监控--xhprof分析

PHP性能监控--xhprof分析

  • xhprof数据如下:
    请求总揽:

函数调用情况:

  • 参数含义

    Inclusive Time 包括子函数所有执行时间。
    Exclusive Time/Self Time函数执行本身花费的时间,不包括子树执行时间。
    Wall时间 花去了的时间或挂钟时间。
    CPU时间 用户耗的时间+内核耗的时间
    Function Name 函数名
    Calls 调用次数
    Calls% 调用百分比
    Incl. Wall Time 调用的包括子函数所有花费时间,以微秒算(一百万分之一秒)
    IWall% 调用的包括子函数所有花费时间的百分比
    Excl. Wall Time 函数执行本身花费的时间,不包括子树执行时间,以微秒算
    EWall% 函数执行本身花费的时间的百分比不包括子树执行时间
    Incl. CPU 调用的包括子函数所有花费的cpu时间。减Incl. Wall Time即为等待cpu的时间减Excl. Wall Time即为等待cpu的时间ICpu% Incl. CPU(microsecs)的百分比
    Excl. CPU 函数执行本身花费的cpu时间,不包括子树执行时间,以微秒算。
    ECPU% Excl. CPU的百分比
    Incl.MemUse 包括子函数执行使用的内存
    IMemUse% Incl.MemUse的百分比
    Excl.MemUse 函数执行本身内存,以字节算
    EMemUse% Excl.MemUse的百分比
    Incl.PeakMemUse Incl.MemUse的峰值
    IPeakMemUse% Incl.PeakMemUse的峰值百分比
    Excl.PeakMemUse Excl.MemUse的峰值
    EPeakMemUse% EMemUse%峰值百分比

  • 数据主要查看的参数是:wall time和cpu time

  • 图片查看:性能有问题的最严重的模块是红色,其次是黄色(可查看附件)

createJs学习之Bitmap 类

createJS之EaselJS教程之3 Bitmap 类

按照显示的属性绘制一幅图,一个视频或者画到画布上,构造函数可以传url或者图片对象。

举例

function drawBitmap() {  
    var stage = new createjs.Stage("demoCanvas");   
    var bitmap = new createjs.Bitmap(img);
    bitmap.cache(0, 0, 500, 500);
    stage.addChild(bitmap);
    bitmap.x = 0;
    bitmap.y = 0;            
    stage.update();         
}  
function init() {  
    window.img = new Image();
    img.src = "./logo.jpg";             
    img.onload = function(){
        drawBitmap();
    }
}

说明

  1. 当图片一定要事先加载完毕才能调用bitmap。
  2. svg源的位图的alpha值只能是0和1,为了绕开这个bug,可以使用位图缓存
  3. svg源的位图如果包涵跨域的数据,会污染canvas(阻止相互交互),除了最新版的firefox,其他浏览器都会触发;
  4. 跨域的图片位图会当发生鼠标点击等交互行为的时候引起如下错误:cross-origin security errors ,你可以如下设置避免:

img.crossOrigin="Anonymous"

rbac与auth权限认证的区别

RBAC是基于角色的权限管理系统。
AUTH是基于节点的权限管理系统。
对于这两种权限管理的认识来自两个不同的系统,PHPCMS V9 与OneThink。
RBAC 可以将不同的用户分配给不同的用户组,即角色,每个角色享有不同的系统管理权限,但是如果角色之间的权限有交差时,可能会出现分工不明的情况,比如,有编 辑与管理员两个组,编辑要求对文章列表有添加与修改的权限,管理员对文章列表有添加与修改及删除操作,还可以进行文章分类的管理,但是如果发现在编辑里有 个主编,我想让他也可以删除文章,而又不想给他文章分类管理的权限,这时候用RBAC系统除了再建立一个用户组以外,没有其它方式,至少我没想到。
而 基于节点的权限管理AUTH就不会有这个问题,因为相对于所有用户来说,每个操作都是一个节点,我可以自由的分配每一个节点给每一个用户,但同时,也会出 现用户组不明确的问题,就是说,没有用户组,只有用户,当然这是原本的问题,其实AUTH也是可以先建立用户组,给用户组分配权限而后再将用户分配到相应 的组里,AUTH里还有个用户组明细表,就是用来对应用户跟组的关系,这样就解决了上边所说的问题,用户没有所在组。用户又可以同时属于不同的组,进而拥 有两个组组合的权限。
其实两种方式最根本的区别在于,RBAC中的用户只能属于一个组,AUTH中的用户可以属于不同的组,到于THINKPHP官网上这篇文章(http://www.thinkphp.cn/topic/4029.html)中说的condition的问题,在V9中也有data附件属性可以操作使用。

RBAC中数据库的基本设计如下:

1、用户角色表role
roleid tinyint(3) unsigned 主 INDEX
rolename varchar(50)
disabled tinyint(1) unsigned 1

2、管理员表admin
adminid mediumint(6) unsigned 主 INDEX
roleid tinyint(3)
adminname varchar(20) INDEX
password varchar(32)
lastloginip varchar(15)
lastlogintime int(10) unsigned
realname varchar(50)
email varchar(50)
tel varchar(20)

3、管理员权限表admin_priv
roleid tinyint(3) unsigned INDEX
m char(20) INDEX
c char(20) INDEX
a char(20) INDEX
data char(30) index
AUTH中数据库的基本设计如下:

1、用户角色表role
roleid tinyint(3) unsigned 主 INDEX
rolename varchar(50)
disabled tinyint(1) unsigned 1
rules varchar(500)

2、管理员表admin
adminid mediumint(6) unsigned 主 INDEX
adminname varchar(20) INDEX
password varchar(32)
lastloginip varchar(15)
lastlogintime int(10) unsigned
realname varchar(50)
email varchar(50)
tel varchar(20)

3、管理员权限表admin_priv
roleid tinyint(3) unsigned INDEX
m char(20) INDEX
c char(20) INDEX
a char(20) INDEX
condition char(100) NOT NULL
4、用户组明细表group_access
adminid mediumint(6) unsigned
roleid tinyint(3) unsigned

ES6 详解

ES6详解

ES6主要改进点

在使用ES6之前,我们使用ES5规范的javascript,那使用过程中有哪些地方是我们觉得比较麻烦的地方,基本上就是ES6改进的点,包括:js继承、数据模板、js模块化、js回调、js异步和一些基本方法不完善等。

一、js继承

ES5通过构造函数,定义并生成新对象。下面是一个例子。

function Point(x,y){
    this.x = x;
    this.y = y;
}
Point.prototype.toString = function () {
    return '('+this.x+', '+this.y+')';
}

ES6引入了Class(类)这个概念,作为对象的模板。通过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)

上面代码定义了一个“类”,可以看到里面有一个constructor函数,这就是构造函数,而this关键字则代表实例对象。这个类除了构造方法,还定义了一个toString方法。注意,定义方法的时候,前面不需要加上function这个保留字,直接把函数定义放进去了就可以了。

Class之间可以通过extends关键字,实现继承。

class ColorPoint extends Point {}

上面代码定义了一个ColorPoint类,该类通过extends关键字,继承了Point类的所有属性和方法。但是由于没有部署任何代码,所以这两个类完全一样,等于复制了一个Point类。下面,我们在ColorPoint内部加上代码。

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 等同于super.constructor(x, y)
    this.color = color;
  }
  toString() {
    return this.color+' '+super();
  }
}

上面代码中,constructor方法和toString方法之中,都出现了super关键字,它指代父类的同名方法。在constructor方法内,super指代父类的constructor方法;在toString方法内,super指代父类的toString方法。

二、模板操作

我们一般如何进行模板替换

<script type="text/html" id="tpl_coupon_show">
    <div class="card_ticket_wrp">
        <div class="card_ticket">
              {data.brand_name}
        </div>
    </div>
</script>

三、js模块化

在ES6之前,js没有模块化的概念,想要使用模块化开发,就需要依赖外部库比如requireJs、seaJs、labJs或者按照AMD或者CMD规范定义自己写类似的定义函数。那ES6是怎么做的了?
ES6实现了模块功能,试图解决JavaScript代码的依赖和部署上的问题,取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案。

模块功能有两个关键字:export和import。export用于用户自定义模块,规定对外接口;import用于输入其他模块提供的功能,同时创造命名空间(namespace),防止函数名冲突。

ES6允许将独立的JS文件作为模块,也就是说,允许一个JavaScript脚本文件调用另一个脚本文件。该文件内部的所有变量,外部无法获取,必须使用export关键字输出变量。下面是一个JS文件,里面使用export关键字输出变量。

// profile.js
export var firstName = 'David';
export var lastName = 'Belle';
export var year = 1973;

上面是profile.js文件,ES6将其视为一个模块,里面用export关键字输出了三个变量。export的写法,除了像上面这样,还有另外一种。

// profile.js
var firstName = 'David';
var lastName = 'Belle';
var year = 1973;

export {firstName, lastName, year};

上面代码在export关键字后,使用大括号输出一组变量,它与前一种写法是等价的。
使用export定义模块以后,其他JS文件就可以通过import关键字加载这个模块(文件)。

import {firstName, lastName, year} from './profile';
function setHeader(element) {
  element.textContent = firstName + ' ' + lastName;
}

四、回调

五、数据绑定

六、异步处理模式

总结

参考
ECMAScript 6入门
es6features

利用gulp打造前端集成开发环境二--代码部署篇

目标

文件需要从原路径到发布路径

步骤

  • 移动文件:在前端工程中,需要解决的有三个问题:

资源定位:获取任何开发中所使用资源的线上路径;
内容嵌入:把一个文件的内容(文本)或者base64编码(图片)嵌入到另一个文件中;
依赖声明:在一个文本文件内标记对其他资源的依赖关系;

以上内容学习至 fis介绍

文件移动功能就是解决资源定位的问题,我们的开发路径和发布路径是有必要不一样的,那么我们开发完成之后需要有一套构建工具自动帮我们完成这项功能。

//变量设置
var jsPath = {
    src : '../static/src/scripts',
    release : '../static/release/scripts'
},cssPath = {
    src : '../static/src/styles',
    release : '../static/release/styles'
},htmlPath = {
    src : '../application/views/m3',
    release : '../application/views/m3/'
},imgPath = {
    src : '../static/src/images',
    release : '../static/release/images/'
};
//移动lib任务
gulp.task('libmove',function(){
    //移动lib第三方库  不压缩
    gulp.src(jsPath.src + '/library/**/*.js')
        .pipe(gulp.dest(jsPath.release + '/library/'));
})

整个代码结构如下:
image

整个static目录分为src和release目录,src放得是源码文件,是不会发布到外网的,release放得是预处理后的文件,包括压缩、混淆、用md5加后缀、less编译、react预处理等操作,是直接发布到外网的。

最后执行 gulp move,那么src下的library文件都移动到了release目录下了。

创业一年总结--需求分析

创业一年半,总结失败的原因,得出成功的三大因素:
1、团队的执行力
2、产品的市场是不是刚需,是不是够大(老大定的方向)
3、在每个关键节点,团队知道什么该做,什么不需要做(老大定的计划)

可以看出老大在整个创业工程中有多么重要了。

下面是我对强需求和若需求的一点分析:

img

利用gulp打造前端集成开发环境二--文件合并篇

目标

若干文件自定义合并

步骤

  • 下载gulp-concat插件
npm install --save-dev gulp-concat
  • 新建一个json文件,叫merge.json,里面包含需要进行合并的文件列表,如下:
[{
    "src": [
            "/lib/jquery.js", 
            "/lib/template.js", 
            "/lib/json2.js",
            "/lib/prototype.js"
        ],
    "dest": "/lib/lib_combo.js"
}]
  • 修改gulpfile,执行任务
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var paths = {
  scripts: {
    source : '../src/js/**/*.js',
    release: '../release/js'
  },
  css : {
    source : '../src/css/**/*.css',
    release : '../release/css'
  },
  html : {
    source : '../src/html/**/*.html',
    release : '../release/html'
  }  
};
process.on('uncaughtException', function(err) {
    console.log(err);
})
/*
 * 文件压缩
 */
gulp.task('move', function() {
 gulp.src(paths.scripts.source,"!" + paths.scripts.source + "/lib/*.js")
    .pipe(uglify())
    .pipe(gulp.dest(paths.scripts.release));
});
//js合并任务(读取合并配置)
gulp.task('merge', function() {
    var data = require('./merge.json');
    data.forEach(function(o) {
        var arr = [];
        o.src.forEach(function(s) {
            arr.push(paths.scripts.source + "/" + s);
        });
        o.src = arr;
        gulp.src(o.src).pipe(concat(o.dest)).pipe(gulp.dest(paths.scripts.release));
    });
});
gulp.task('default', ["merge","move"], function() {

});

同时看到我们把move任务中取出了common/lib文件夹的处理。

Javascript线程的理解

单线程的JS引擎

JS单线程原因:如果多线程,那么删除或者创建dom元素,都需要在线程之间通信。因为浏览器不确定dom状态。所以,js设计之初就是单线程。
好处:简单,没有线程切换维护开销,省内存。

多线程的浏览器

  1. JS引擎线程
  2. 界面渲染线程
  3. 浏览器事件触发线程
  4. Http请求线程

浏览器一般至少实现三个常驻线程:JS引擎线程,GUI渲染线程,浏览器事件触发线程。

  1. JS引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。
  2. GUI渲染线程负责渲染浏览器界面,当界面需要重排、重绘或由于某种操作引发回流时,该线程就会执行。但需要注意 GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
  3. 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。

JS引擎的工作机制是:当线程中没有执行任何同步代码的前提下才会执行异步代码,setTimeout是异步代码,所以setTimeout只能等JS引擎空闲才会执行,但死循环是永远不会空闲的,所以setTimeout也永远不会执行。

一道面试题:js中在一个时间节点执行

var startTime = +(new Date()),endTime;
setTimeout(function(){
    endTime = +(new Date());
    console.log(1);
    console.log(endTime - startTime);
    },3000);
setTimeout(function(){
    endTime = +(new Date());
    console.log(2);
    console.log(endTime - startTime);
    },2000);
while(+(new Date()) - startTime < 5000){}
console.log(+(new Date()) - startTime);

请问alert(1)和alert(2)的先后顺序和时间间隔。

5s钟的同步执行完之后,开始执行setTimeout异步代码,因为第二个插入的时间间隔早,先执行。
image
因为5s时间超过了3s,所以两个函数几乎同时执行。如果同步时间是1s,那就是2s之后执行第二个函数,3s后执行第一个函数。
image

setTimeout(function(){},0)

setTimeout(..) 并没有把你的回调函数挂在事件循环队列中。它所做的是设 定一个定时器。
当定时器到时后,环境会把你的回调函数放在事件队列中,如果这时候事件循环中已经有 20 个项目了会怎样呢?你的回调就会等待,定时器只能确保你的回调函数不会在指定的 时间间隔之前运行,但可能会在那个时刻运行,也可能在那之后运行,要根据事件队列的 状态而定(PS: 这就是造成定时器不准确的缘由)。

setTimeout(..0)(hack)进行异步调度,基本上它的意思就是把这个函数插入到当前事件循环队列的结尾处。

centos命令一键搭建lamp环境

首先为了搭建一个稳定的lamp的练习环境,确保你的虚拟机可以连网,这里我们使用的yum安装,它可以帮助我们解决软件自己的依赖关系.我还在后面加了postgresql数据库如果不需要的话可以去掉和postgresql的参数.命令如下yum -y install httpd mysql mysql-server php php-mysql postgresql postgresql-server php-postgresql php-pgsql php-devel,

一些常见的编码小技巧整理

1、重复字符串的创建
// 创建32个0的商品ID

new Array(33).join('0');
// 即,创建N个重复字符串
new Array(N + 1).join(repeater);

2、判断是否闰年

var year = 2008;
new Date( +new Date( year, 2, 1 ) - 1 ).getDate() === 29

3、使用a标签内置的机制来解析url地址
这是一个使用a标签内置的机制来解析url地址的方法,大家或许平时都在用string和正则的方法来处理url解析,其实浏览器本身就具有解析url的能力,快来看看吧

var parser = document.createElement('a');
parser.href = "http://example.com:3000/pathname/?search=test#hash";

console.log(parser.protocol); // => "http:"
console.log(parser.hostname); // => "example.com"
console.log(parser.port);     // => "3000"
console.log(parser.pathname); // => "/pathname/"
console.log(parser.search);   // => "?search=test"
console.log(parser.hash);     // => "#hash"
console.log(parser.host);     // => "example.com:3000"

4、获取服务器端的时间
巧妙利用http请求的head方法来让服务器端返回时间,不用额外的去开发后端接口。 不过这种做法有一点风险: 1、服务器的时间要有同步,不然可能在路由到不同服务器的时候出现不同的时间结果 2、确认服务器的gzip配置是否正常,否则会导致下一个异步请求出错。

function $getServerTime(url) {
    var xhr = $xhrMaker(), url = url || "http://" + window.location.hostname+"/favicon.ico";
    try{
        xhr.open("HEAD", url, false);
        xhr.send();
    }catch(e){
        return new Date();
    }
    return new Date(xhr.getResponseHeader("Date"));
}

5、获取对象类型

function getType(obj) {
        return obj === null ? 'null' : (obj === undefined ? 'undefined' : Object.prototype.toString.call(obj).slice(8, -1).toLowerCase());
      }

6、短小精悍的微型模板引擎
一个简单的模板引擎。它设计精巧,支持普通变量填充与循环,代码量很小,同时支持传入模板字符串及从页面的隐藏textarea取模板内容。

function $SimpleTemplate() {
    return {
        /**
         *使用JSON数据填充模板
         *@param {object}   json    json对象
         *@param {string}   tpl     模板字符串
         *@example  
         *@return   替换结果字符串
         */
        parse : function(json,tpl,splitStr)
        {
            var blocks=[];  

            for(var i=0,len=json.length; i<len; i++){="" blocks.push(tpl.replace(="" {(\w+)}="" g,function(a,="" b){="" return="" json[i][b]="" !="=" undefined="" ?="" :="" a;="" }));="" }="" *$$.each(json,function(i,="" el){="" blocks.push($strtrim(tpl).replace(="" el[b]="" })*="" blocks.join(splitstr="" ||="" '');="" },="" **="" *="" *@param="" {object}="" json="" json对象="" {string}="" target="" 目标填充元素id="" tpl="" 模板textarea的id,也可以直接传入模板内容="" stuff="" function(json,target,tpl,splitstr)="" {="" '#'+target+'_tpl').val();="" var="" *传入的模板内容*="" $id(target+'_tpl').value="" *从隐藏的textarea取*="" ;="" m="tpl.match(/<#([\s\S]+)#">/);
            var allTpl = m ? m[0] : tpl;
            var blockTpl= m ? m[1] : tpl;
            var html = tpl.replace(allTpl, this.parse(json, blockTpl, splitStr));
            var dom = document.getElementById(target);
            if (dom) dom.innerHTML = html;
        }
    };
}
function $id(id){
    return typeof(id)=="string"?document.getElementById(id):id;
}
</len;>

未完待续

phalapi-进阶篇2(DI依赖注入和单例模式)

前言

先在这里感谢phalapi框架创始人@dogstar,为我们提供了这样一个优秀的开源框架.

离上一次更新过去了快两周,在其中编写了一个关于DB分表分库解决大数据量的拓展,有兴趣的童鞋可以了解了解.废话不多说,本小节在于解释一下在PhalApi框架中两个比较好的**,单例模式和依赖注入.

  1. 单例模式

单例模式对于长期进行过面向对象编程的童鞋应该不算陌生,在学习php的童鞋也应该有听过,这里简单的聊一聊单例模式到底是一个怎么样东西,解决了什么问题,并且在PhalApi中是如何实现的.

单例单例,所谓单例也就是有且只有一个存在,这就是单例,不难看出他的好处资源利用少因为只有一个,大家都是知道要使用一个类必须要实例他也就是new在每次new一个对象的时候都会在内存中生成一块区域来存放这个实例,如果在程序一次运行中使用了很多的new实例化了同一个对象,那就比较消耗资源了,但是如果是通用一个使用全局变量global程序又会显得不优雅而且会很乱,在这种情况下单例模式就产生了.

单例模式就是一个两全其美的一个方法既可以全局通用,二不用担心占用过多的资源,三又非常优雅,我们来一起看看在PhalApi中是如何实现单例模式的:

//大家看到我们常用的DI方法内部实现的是PhalApi_DI中的静态方法one方法
function DI() {
return PhalApi_DI::one();
}

然后我们看向one方法内部

每当我们请求过来的时候先验证静态变量instance是不是没有被初始化,如果是第一次调用他会在内部去实例化PhalApi_DI类然后负值给$instance然后返回实例好的这个静态变量,当我们下次在请求过来的时候这个静态变量已经被实例化好了就会直接跳过实例的过程直接返回这个对象,也就是我们在PhalApi框架所有的地方使用的DI方法其实都是一个对象,在内存中只存在一块区域,代码如下:

public static function one(){
if(self::$instance == NULL){
self::$instance = new PhalApi_DI();
self::$instance->onConstruct();
}

return self::$instance;

}

其实不难我们只用吧new一个类的操作封装到我们需要new的类的静态方法在向上面一样的去判断,就可以很简单的去实现单例模式.
2. 依赖注入

依赖注入又称之为"控制反转",如果是熟悉javaweb开发的spring框架应该有比较深的感触,在这里也不往深的讲,就简单讲解一下PhalApi中DI依赖注入的实现让大家了解这种设计模式如何实现以及自此基础上实现的惰性加载机制.
2.1 DI依赖注入实现

大家在PhalApi中常用的DI()方法,也就是采用我们上面所谓的单例模式不用多说了,也就是我们每次使用DI()其实就是在使用PhalApi_DI类,那么我们依赖注入的关键也就是在PhalApi_DI之中

先来讲一下他的一个实现方式在来讲具体实现,这里举个例子:

//配置
DI()->config = new PhalApi_Config_File(API_ROOT . '/Config');

其实在内部有一个数组,它吧config作为了key,吧new PhalApi_Config_File(API_ROOT . '/Config')作为了value然后保存了起来当我们下一次使用DI->config->get();的时候它就会根据key值config拿出开始new好的类,所以可以说config操作是依赖于DI(),而且在使用DI()->config的时候永远都是在使用的一个实例,也能减少资源的消耗.

有的童鞋就好奇了为什么DI()->config会存到数组需要的时候会拿出来呢,感兴趣的童鞋可以百度一下魔法方法ser和get

/**大家可以看到这是PhalApi_DI中的魔法方法__set

  • 也就是当使用DI()->config = new PhalApi_Config_File(API_ROOT . '/Config');的时候
  • 获得的name值就是config,获得的value也就是new PhalApi_Config_File(API_ROOT . '/Config');
    */get同理,在内部实现都是调用了内部get和set方法
    public function __set($name, $value){
    $this->set($name, $value);
    }

public function __get($name){
return $this->get($name, NULL);
}

看完之后大家是不是觉得很简单啊,大家以后也可以在自己设计类的时候采用这种灵活的魔法方法实现.
2.2 惰性加载

在PhalApi中的DI()方法也提供惰性加载,惰性加载如字意也就是当类没有被使用到的时候不会加载,这样的操作也是为了避免浪费不必要的资源,当我们不是用的时候永远不会去实例化只有当你使用到的时候才会去new这个类然后实例化之后使用,我们来看看是如何实现的.

//当我们执行以下语句的时候,在依赖注入的时候存的是value值是字符串的test
DI()->test = 'test';

//使用DI()->test->test();的时候会使用到PhalApi中的get方法,在get方法中有一段代码
$this->data[$key] = $this->initService($this->data[$key]);

//在initService方法内部验证了value是字符串就实例化了再返回

if($config instanceOf Closure){
$rs = $config();
}elseif(is_string($config) && class_exists($config)){
$rs = new $config();
if(is_callable(array($rs, 'onInitialize'))){
call_user_func(array($rs, 'onInitialize'));
}
}else{
$rs = $config;
}

作者: PhalApi
链接:http://www.imooc.com/article/6113
来源:慕课网

window.performance 详解

window.performance详解

performance的作用

浏览器暴露给js的一个接口,可以通过这个接口查看用户访问网站的连接建立时间、dns时间等信息。使用该api时需要在页面完全加载完成之后才能使用,最简单的办法是在window.onload事件中读取各种数据,因为很多值必须在页面完全加载之后才能得出。

浏览器支持情况

IE9和chrome6以上的版本都支持:

  • pc端
  • window.performance : ie9
  • window.webkitPerformance : chrome6-9
  • window.performance : chrome10+
  • 移动端
  • android4.0

各个值的详细含义

img
可以看到api的接口定义如下:

memory:浏览器内存情况

  1. jsHeapSizeLimit
  2. totalJSHeapSize
  3. usedJSHeapSize
    注:usedJSHeapSize表示所有被使用的js堆栈内存;totalJSHeapSize表示当前js堆栈内存总大小,这表示usedJSHeapSize不能大于totalJSHeapSize,如果大于,有可能出现了内存泄漏

navigation :网页导航相关

  1. redirectCount:重定向属性
    一个只读属性,返回当前页面是几次重定向才过来的。但是这个接口有同源策略限制,即仅能检测同源的重定向。
  2. type
    返回值应该是0,1,2 中的一个。分别对应三个枚举值:

    0 : TYPE_NAVIGATE (用户通过常规导航方式访问页面,比如点一个链接,或者一般的get方式)

    1 : TYPE_RELOAD (用户通过刷新,包括JS调用刷新接口等方式访问页面)

    2 : TYPE_BACK_FORWARD (用户通过后退按钮访问本页面)

timing :测速相关

img

navigationStart:准备加载新页面的起始时间
redirectStart:如果发生了HTTP重定向,并且从导航开始,中间的每次重定向,都和当前文档同域的话,就返回开始重定向的timing.fetchStart的值。其他情况,则返回0
redirectEnd:如果发生了HTTP重定向,并且从导航开始,中间的每次重定向,都和当前文档同域的话,就返回最后一次重定向,接收到最后一个字节数据后的那个时间.其他情况则返回0
fetchStart:如果一个新的资源获取被发起,则 fetchStart必须返回用户代理开始检查其相关缓存的那个时间,其他情况则返回开始获取该资源的时间
domainLookupStart:返回用户代理对当前文档所属域进行DNS查询开始的时间。如果此请求没有DNS查询过程,如长连接,资源cache,甚至是本地资源等。 那么就返回 fetchStart的值
domainLookupEnd:返回用户代理对结束对当前文档所属域进行DNS查询的时间。如果此请求没有DNS查询过程,如长连接,资源cache,甚至是本地资源等。那么就返回 fetchStart的值
connectStart:返回用户代理向服务器服务器请求文档,开始建立连接的那个时间,如果此连接是一个长连接,又或者直接从缓存中获取资源(即没有与服务器建立连接)。则返回domainLookupEnd的值
(secureConnectionStart):可选特性。用户代理如果没有对应的东东,就要把这个设置为undefined。如果有这个东东,并且是HTTPS协议,那么就要返回开始SSL握手的那个时间。 如果不是HTTPS, 那么就返回0
connectEnd:返回用户代理向服务器服务器请求文档,建立连接成功后的那个时间,如果此连接是一个长连接,又或者直接从缓存中获取资源(即没有与服务器建立连接)。则返回domainLookupEnd的值
requestStart:返回从服务器、缓存、本地资源等,开始请求文档的时间
responseStart:返回用户代理从服务器、缓存、本地资源中,接收到第一个字节数据的时间
responseEnd:返回用户代理接收到最后一个字符的时间,和当前连接被关闭的时间中,更早的那个。同样,文档可能来自服务器、缓存、或本地资源
domLoading:返回用户代理把其文档的 "current document readiness" 设置为 "loading"的时候
domInteractive:返回用户代理把其文档的 "current document readiness" 设置为 "interactive"的时候.
domContentLoadedEventStart:返回文档发生 DOMContentLoaded事件的时间
domContentLoadedEventEnd:文档的DOMContentLoaded 事件的结束时间
domComplete:返回用户代理把其文档的 "current document readiness" 设置为 "complete"的时候
loadEventStart:文档触发load事件的时间。如果load事件没有触发,那么该接口就返回0
loadEventEnd:文档触发load事件结束后的时间。如果load事件没有触发,那么该接口就返回0

组合值的意义

DNS查询耗时 :domainLookupEnd - domainLookupStart
TCP链接耗时 :connectEnd - connectStart
request请求耗时 :responseEnd - responseStart
解析dom树耗时 : domComplete - domInteractive
白屏时间 :responseStart - navigationStart
domready时间 :domContentLoadedEventEnd - navigationStart
onload时间 :loadEventEnd - navigationStart

performance.getEntries 资源测速

img
比如图中type为img的图片整个加载时间为duration ms。
可以通过这个接口统计整个页面有多少img、css、js以及对应的下载时间等信息。

常用统计方法

performance 测速上报

     /**
 * 上报Performance timing数据;
 * 如果某个时间点花费时间为0,则此时间点数据不上报。
 * @param {String}
 *            f1 flag1简写,测速系统中的业务ID,譬如校友业务为164
 * @param {String}
 *            f2 flag2简写,测速的站点ID
 * @param {String}
 *            f3_ie flag3简写,测速的页面ID
 *(因为使用过程中我们发现IE9的某些数据存在异常,
 * 如果IE9和chrome合并统计,会影响分析结果,所以这里建议分开统计)
 * @param {String}
 *            f3_c flag3简写,测速的页面ID
 * (如果为空,则IE9和chrome合并统计)
 */
function setTimingRpt(f1, f2, f3_ie, f3_c){     
    var _t, _p = (window.webkitPerformance ? window.webkitPerformance : window.msPerformance), _ta = ["navigationStart","unloadEventStart","unloadEventEnd","redirectStart","redirectEnd","fetchStart","domainLookupStart","domainLookupEnd","connectStart","connectEnd","requestStart",/*10*/"responseStart","responseEnd","domLoading","domInteractive","domContentLoadedEventStart","domContentLoadedEventEnd","domComplete","loadEventStart","loadEventEnd"], _da = [], _t0, _tmp, f3 = f3_ie;  
    _p = (_p ? _p : window.performance);        
    if (_p && (_t = _p.timing)) {       
        if (!_t.domContentLoadedEventStart) {
            _ta.splice(15, 2, 'domContentLoaded', 'domContentLoaded');
        } else {
            if (f3_c) {
                f3 = f3_c;
            }
        }           
        _t0 = _t[_ta[0]];
        for (var i = 1, l = _ta.length; i < l; i++) {
            _tmp = _t[_ta[i]];
            _tmp = (_tmp ? (_tmp - _t0) : 0);
            if (_tmp > 0) {
                _da.push( i + '=' + _tmp);
            }
        }           
        if (window.d0) {//统计页面初始化时的d0时间
            _da.push('30=' + (window.d0 - _t0));
        }           
        var url = 'http://www.report.com?flag1=' + f1 + '&flag2=' + f2 + '&flag3=' + f3 + '&' + _da.join('&');      
        var _img = new Image();
        setTimeout(function(){
            _img.src = url;
        }, 10);
    }       
};
//注意!需要在onload事件后进行计算上报。
window.onload = function(){
    setTimingRpt(7839, 7, 3);//活动页面
};

performance chrome可视化插件

performance chrome可视化插件

未完待续!!
参考:

HTML5 performance API 草案
Resource Timing

移动端前端常见bug及解决方案

  • 防止safari和WP浏览器下文字在横竖屏切换时尺寸发生变化
body { -webkit-text-size-adjust : none; -ms-text-size-adjust : none; }
  • 去除在IE9以上浏览器中a标签点击时的灰色背景
a { background-color : transparent; }
  • 去除手机超链接点击背景色
WP手机:<meta name="msapplication-tap-highlight" content=no/>
Webkita { -webkit-tap-highlight-color : transparent; }
  • 长按时不触发系统菜单
img { -webkit-touch-callout : none; }
  • 去除IOS下input元素的内阴影
input { -webkit-appearance : none; }
  • 内容垂直居中

内容垂直居中一般用于弹出层,如果尺寸固定的话,用CSS绝对定位就可以搞定,但是如果尺寸是不固定的,就需要使用js动态定位。
其实在移动端还可以使用display:box;就可以轻松的让内容垂直居中,如下:

<div class="box">
    <div class="content">
        <p>我是内容-1</p>
        <p>我是内容-2</p>
    </div>
</body>
<style>
.box {
    width:800px;height:600px;background:red;
    display : -webkit-box;
    -webkit-box-orient : horizontal;
    -webkit-box-pack : center;
    -webkit-box-align : center;
    display : -moz-box;
    -moz-box-orient : horizontal;
    -moz-box-pack : center;
    -moz-box-align : center;
}
</style>
  • IOS弹出虚拟键盘时候,自动小写

在IOS系统中,当我们点击输入框拉起虚拟键盘的时候,默认情况下对于英文输入法键盘是开启了首字母大写功能的。但是在我们项目里面为了更好的体验需要默认将该特性去掉。此时,可以使用移动webkit浏览器支持的特性将其去除:在input元素上添加autocapitalize属性。通过使用autocapitalize="off"来关闭默认虚拟键盘首字母大写。如果要开启,可以使用 autocapitalize="on"。

<div class="ui-searchbar-input"><input value="" type="text" placeholder="请输入游戏名称" autocapitalize="off"></div>
  • 输入框输入字符监听

IOS下,输入英文情况下,回退清除字符不会触发keypress事件,android下可以。此外,IOS下切换为中文输入法时候,输入过程中输入框对产生的字母会响应keypress,但是对于单击选择中文到输入框后后不会触发keypress事件。以此类推,剩下的keyDown、keyUp事件都差不多。
总结:keyPress之类的键盘事件监听不适合移动端的虚拟键盘监听,总是会引发这种或者那种问题。

在手机上实时捕获用户输入搜索框的内容明显跟PC有区别的,最大的不同就是PC有实体键盘,而移动web捕获的是虚拟键盘。既然键盘事件不行,那么我们就从Input元素输入框入手,看看有什么事件可以利用。
onpropertychange事件:该事件是IE浏览器特供,只要当前对象属性发生改变(例如输入框文案),都会触发事件,webkit就忽略吧。
onchange事件: webkit可以用,但是只有当当前元素失去了焦点后,才会去校验属性是否有更改,才会触发这个事件(也就是说一直输入内容是不会触发该事件的,也许select元素标签适合这个特性),明显不符合用户输入体验。
oninput事件: chrome webkit也可以使用,IE9+也可使用。也是表示输入时候内容一旦有变更就实时触发,而且不会受限于必须失去焦点才会触发的制约。

oninput事件bugfix总结:
1、在IOS下,输入中文点击选择后会连续触发两次oninput事件,android下我使用的机型未出现该问题
2、在IOS下,中文输入法输入英文时候,字母之间会出现一个类似于空格的东东,研究了一下这种空格可以称之为“六分之一空格”

/**
 * 对于用户在Input框里面的输入进行过滤,例如 1、对于IOS六分之一空格情况 2、对于IOS输入中文时候会连续两次触发onInput情况
 * 
 * @param str {String} 从input框读取的值
 * @returns {String} 返回过滤后的值
 * 
 */
function filterString(str) {
    if (!isAndroid) {
        // IOS下需要做的处理
        var cache = arguments.callee;
        var curTime = new Date().getTime() / 1000;
        // 当前搜索的字符串在这个delta
        // ms时间区间里面如果跟最近的一次搜索字符串相同,则不对该结果进行响应,解决情况2问题
        var delta_time = 400;
        // 保存当前的字符串信息
        var keyObj = {
            str : str,
            time : curTime
        };

        if (cache.keyObj && cache.keyObj.str == str) {
            // 读取最近一次的字符串信息
            var lastTime = cache.keyObj.time;
            if (curTime - lastTime < delta_time) {
                // 此时可认为丢弃此次相同关键字查找
                return "";
            }
            // 重新更新cache
            cache.keyObj = keyObj;
        } else {
            // 这是新开页面的第一次成功检索或者和最近一次检索的字符串是不一样的关键字
            // 更新cache
            cache.keyObj = keyObj;
        }

        // 接着进行六分之一空格的处理
        str = str.replace(/\u2006/g, "");
    }

    return str;

}
  • CSS单位:vw、vh、vmin、vmax

vm和vh:这两种单位是以视窗(viewpoint)的宽度和高度为基准,1vw = 1/100 视窗宽度,1vh = 1/100 视窗高度,举个栗子:如果浏览器的视窗宽高分别为1000px和900px,那么1vw = 1000/100 = 10px、1vh = 900/100 = 9px。如果想让一个元素占据全屏,你可以这样:

<div class="content">
    <h2>标题文字</h2>
    <p>我是内容-1</p>
    <p>我是内容-2</p>
</body>
<style>
*{margin:0;padding:0;}
.box {
    position:absolute;top:0;left:0;background:red;
    width: 100vw;
    height: 100vh;
}
</style>

vmin:vmin的值是当前vw和vh中较小的值。
vmax:vmax的值是当前vw和vh中较大的值。

利用gulp打造前端集成开发环境二--文件压缩篇

目标

在对文件内容进行压缩
js采用uglify混淆压缩

步骤

  • 安装gulp-uglify插件
npm install gulp-uglify --save-dev
  • 修改gulpfile文件执行任务
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var paths = {
  scripts: {
    source : '../src/js/**/*.js',
    release: '../release/js'
  },
  css : {
    source : '../src/css/**/*.css',
    release : '../release/css'
  },
  html : {
    source : '../src/html/**/*.html',
    release : '../release/html'
  }  
};
process.on('uncaughtException', function(err) {
    console.log(err);
})
/*
 * 文件压缩
 */
gulp.task('move', function() {
  gulp.src(paths.scripts.source)
    .pipe(uglify())
    .pipe(gulp.dest(paths.scripts.release));
});
gulp move

这样就完成了在文件移动过程中的压缩操作了。查看被压缩的情况:

define("home/index",["home/b","home/c"],function(e){alert(1);var c=e("home/b"),a=e("home/c");a.callback(),c.callback()});

前端框架学习

前端框架学习

常见的前端框架分析
框架需要解决哪些问题?
设计框架从哪些方面入手?

到现在为止,前端框架有以下五类:

prototype 类

这类框架

jQuery 类

以dom操作为中心,jQuery就是一个选择器,通过批量选择HTMLELEMENTS对象进行操作,可以很方便的对页面进行管理。

seajs 类

前端模块框架的代表

backbone 类

agular 类

已数据为中心

react 类

mac环境charles工具破解版下载及https抓包配置

我的mac环境的charles版本是3.9.1。希望配置移动端代理https抓包。
分享mac下charles破解安装包
image
http抓包配置:
1、打开charles,proxy->proxy settings。端口配置8888。
image
2、查看当前电脑的ip,在终端输入ifconfig
image
当前ip为192.168.31.125。打开手机wifi设置,设置da代理:192.168.31.125,端口8888。
image
这时候在手机上打开需要抓包的网页,charles会弹出一个是否允许的框,点击允许即可抓包。

https抓包配置:
1、下载charles证书,见微云链接,或者去官网下载,导入手机,不能用微信导入手机,因为微信会阻断文件执行,有邮件的方式发送手机,打开即可安装。
2、charles->tools->proxy setting。勾选enable ssl proxy。点击add,添加域名和端口(443)。
image
3、在手机上配置代理。成功。
image

test

啥地方是否

createJs学习之Graphics 类

createJS之EaselJS教程之1--Graphics 类

Graphics类作用于创建并绘制到网页具体位置的矢量图形。比如你可以通过使用Graphics类中的draw方法绘制图形,然后使用Shap对象轻松地将矢量图形放置到指定的canvas之中。

举例

var g = new createjs.Graphics();        //实例化一个Graphics类
g.setStrokeStyle(1);    //1像素的画笔
g.beginStroke(createjs.Graphics.getRGB(0,0,0)); 
//等同于g.beginStroke('#f00');画边
g.beginFill(createjs.Graphics.getRGB(255,0,0));     //用红色填充图形
g.drawCircle(0,0,50); //画一个半径是50的圆

var s = new createjs.Shape(g);  //将圆实例成一个shape
    s.x = 100;  //横坐标为100
    s.y = 100;  //纵坐标为100
stage.addChild(s);
stage.update();     //update把stage的改动更新到canvas里

Graphics类里的所有绘图方法都会返回一个graphics实例,因此可以使用链式操作。下面这段代码能够绘制出红边蓝色填充的矩形,并放置到指定的context2D中。

var canvas = document.getElementById("demoCanvas");
var cxt = canvas.getContext("2d");
var myGraphics = new createjs.Graphics();
myGraphics.beginStroke("#F00").beginFill("#00F").drawRect(20, 20, 100, 50).draw(cxt);

Graphics类支持简写方法,官方称为tiny api:





























TinyMethodTinyMethod
mtmoveTo lt lineTo
a/atarc / arcTo btbezierCurveTo
qtquadraticCurveTo (also curveTo) rrect
cpclosePath cclear
fbeginFill lfbeginLinearGradientFill
rfbeginRadialGradientFill bfbeginBitmapFill
efendFill sssetStrokeStyle
sbeginStroke lsbeginLinearGradientStroke
rsbeginRadialGradientStroke bsbeginBitmapStroke
esendStroke drdrawRect
rrdrawRoundRect rcdrawRoundRectComplex
dcdrawCircle dedrawEllipse
dpdrawPolyStar pdecodePath

使用简写方法,刚刚那个链式操作的代码可以更简化一下:

var canvas = document.getElementById("demoCanvas");
var cxt = canvas.getContext("2d");
var myGraphics = new createjs.Graphics();
myGraphics.s("#F00").f("#00F").r(20, 20, 100, 50).draw(myContext2D);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.