中午看了一下分享的wx消息架构设计文章,深有感触,但由于内容比较XX,不能分享,这里写一些简单总结
1、为了规避消息的ack,server只通知client 有消息了,client自己拉取消息。
2、client拉取消息带上当前最大自己最大id,防止消息丢失。这个设计的很好
3、client运行时通知策略和类apns通知策略的不同方式
4、优化的通知带内容体的方式,需要ack
      真是两篇好文,可是…,我只能默默的享受了。接下来遇到个问题,如果用户有10w,每个server只有2w的连接,那这10w是怎么安排哪些用户连接哪个server呢。中午问了richard,说根据dns,那分析如下
      dns不是一个好方法,通过dns获取域名的ip列表,轮询ip地址连接。这个有个问题,如果某一个ip机器挂掉了,需要剔除某ip需要修改dns,而dns生效很慢。且这种方式不能对server做权重控制。
      一开始自己意淫的方式,向某server发起连接获取一个相对性能较好的ip及端口,再向该ip发起连接请求,但这种方式需要两次连接,后来问了一个运维朋友,发了一篇文章: LVS负载均衡原理和算法详解 可以利用DR/TUN方式来实现,但具体在client上还不清楚有什么样的解决方案。

19 / 09 / 2014 buling

      发现wordpress慢是一个很大的问题,特开一博来总结优化的相关方法,介于我也是在优化中更新的,此文会长期更新。
一、优化博客中插件加载的js位置。
      很多插件在header中注册了js脚本,但希望脚本放在footer部分加载,如果修改插件可能会影响插件的升级,下面的方法来自于stackoverflow : How to put my javascript in the footer
【方法】把下面的代码添加到 主题中的functions.php中

remove_action('wp_head', 'wp_print_scripts');
remove_action('wp_head', 'wp_print_head_scripts', 9);
remove_action('wp_head', 'wp_enqueue_scripts', 1);
add_action('wp_footer', 'wp_print_scripts', 5);
add_action('wp_footer', 'wp_enqueue_scripts', 5);
add_action('wp_footer', 'wp_print_head_scripts', 5);

N、其它技巧
1、博客中投放了百度广告,延迟异步加载的方法:现在header中加一个全局变量

var onLoadCalls = [];

再在小工具中或其它部分

onLoadCalls.push(function(){
    loadScript("http://cpro.baidu.com/cpro/ui/c.js",function(){
         BAIDU_CLB_DUP2_fillSlotAsync('u432452', 'sidebar-ad'); //sidebar-ad为广告展示的div#id
    });
});

接下来在尾部的js代码中添加如下代码

function loadScript(src, callback){
    var doc = document,
        body = doc.body,
        //创建一个新script来加载
        script = doc.createElement('script');
    script.type = 'text/javascript';
    script.src = src;
    script.onerror = script.onload = script.onreadystatechange = function(e){
        e = e || window.event;
        if(!script.readyState || /loaded|complete/.test(script.readyState) || e === 'error'){
            callback(src);
            script.onerror = script.onload = script.onreadystatechange = null;
        }
    };
    body.appendChild(script);
}
$(document).ready(function(){
    if(onLoadCalls && onLoadCalls.length){
        $.each(onLoadCalls, function(index, fn){
            fn.call(null, $);
        });
    }
});

上次有人说博客好丑,我仔细看了看,确实挺丑的/撇嘴。这一年来发现审美也有提高,很喜欢极简风格的事物,可是创造对我来说难度还是挺大,昨天中午搜了一下wordpress主题,知乎有:有哪些好看的极简的 WordPress 主题?,顶楼提供了自己博客,我看了一下,确实很漂亮,之前apple官网也用了类似线条来描述,但楼上不开源,唉,这….。
还好我们有微创新,其作用在于把别人好的东西抄过来发扬光大,这不,现在的主题(buling,姑且叫这个名字)出来了,这个主题是基于 chitose 更改过来的,基本没有原主题的特点了。
主题对不同屏做了适配,主要针对 大显示器/pad/手机浏览三种
目前主题设置包括如下几项:
1、影藏右边栏。隐藏掉也挺好看的
2、文章列表支持只显示N字长的摘要
3、页脚统计代码或备案信息等。
看到的表象就这么多了,主题由于是花昨天下班时间和今天中午午休时间赶出来的,所以肯定还有很多BUG,比如兼容性,我看了一下IE7还算正常,IE6就算了,我就不打算去支持了。so…现在还没有正式的主题供大家下载使用。
——————————–技术分割线—————————————
这也是第一次去学习wordpress主题开发,其中也涉及到很多api的使用,已经主题的一些设置配置信息,比如这篇文章:zh-cn:主题开发 这网站文章还是很不错,但访问速度实在是难受极了。
一、设置主题信息
在style.css中头部添加如下信息

/*
Theme Name: buling
Theme URI: http://www.mjix.com/archives/1417.html
Author: buling
Author URI: http://mjix.com
Description: 从chitose主题更改,铃不铃极简风格!
Version: 1.0
*/

二、设置主题预览图
截图screenshot.png放在主题根目录
三、设置主题相关信息
主题设置代码直接写在functions.php

//设置主题相关信息
update_option('buling_key', $_POST[$opt]);
//获取主题相关设置
get_option('buling_key');
//注册侧边栏信息
register_sidebar(array(
    'name' => 'Topbar',
    'before_title' => '

', 'after_title' => '

' )); //include sidebar.php文件 get_template_part('sidebar'); //echo,第二个参数可以启用多语言支持 _e('some msg!'); //return some msg __('some msg');

还有一堆the_xxx的api就不一一列举了,基本来说开发一套主题还是比较简单的,第一次可以拿一个现有主题来修改,很快就熟悉了。

16 / 09 / 2014 buling

      隔三差五就会这样,我到底要做点什么呢? 急需寻求一位设计朋友,有想法的设计朋友。
我想:
1、做一个视频下载网站/软件下载,当然只能放国外了,赚点广告费就行了
2、最近喜欢上旅游,希望做一个类似蝉游记类网站,但要更有展示创意,更有用户活跃度的社区
3、深圳实时公交 公众号已经突破1300人了,但一直还没有时间重构,设计师在哪里
4、做点智能硬件产品,现在很多硬件产品都在 gps/重力感应/陀螺仪等去做手环类产品,那不是我想要的
5、做一些线下事情,虽然线上才是强项,但总觉得很虚,开个什么店;5金/手机电脑科技产品/精品茶点小吃类。
这种想法跟大姨妈似的没事就折腾一下,很是痛苦,不知道什么时候才能挣扎出来。
技术不是全部,运用到产品才是根本
【后记】
      这些年,陆陆续续折腾了不少不成型的产品,但最终都是不了了之,一个人的精力总是有限的,专业的人做专业的事情太有必要了。
最近也有两个朋友让过去做一些事情,也是犹豫不绝,不知何去何从

      有时候在ipad或者android等移动设备上需要查看网页源代码,但移动设备本身是不支持查看,只能通过代码方式,之前一直用国外一款工具(忘了名字),但感觉有点慢,所以就根据geshi提供的api,自己搭建了一个,访问地址:http://www.mjix.com/code/viewsource/
      有时候看一些电影下载网站,页面看不到下载链接,只能通过查看源代码的方式获取链接地址,在ipad上很是不方便,通过这个工具查看源代码就方便很多。
怎么安装呢?
方法一:通过电脑收藏夹同步到IPAD等设备。拖动下面的链接到你的收藏夹中:
View Source
方法二:直接添加到收藏夹
1、添加当前页面到你的收藏夹中
2、点击  这个文件查看收藏夹代码  并且复制代码
3、修改刚刚添加到收藏夹中的“查看源代码”,粘贴代码到URL中,保存。

提供api为:http://www.mjix.com/code/viewsource/?uri=$url

      之前一直想做一个文字粒子效果的淡出淡进,这两天事情不多就写了一下代码,效果地址:http://www.mjix.com/code/canvas-text/,按F11进入全屏,做屏保还可以,预览图

======================已更新==========================
      由于之前版本,像素点是通过fillRect来实现,性能有严重问题,会卡顿,cpu直接能飙到25左右,新版通过生成imagedata,再putImageData来达到更新效果。
      主要是在粒子(文字像素点)的位移问题上的处理方法。淡进前需要先获取到像素点的初始位置极其透明度,这个东东运用到数学左边换算问题,要遇到数学有点头大就跳过吧

     //获取渐进前的像素点位置
    getInData : function(data, min, offset){
        var xs = [],
            ys = [];
        this.each(data, function(info, index){
            xs.push(info[0]);
            ys.push(info[1]);
        });
        var max = Math.max.apply(xs, xs),
            mix = Math.min.apply(xs, xs),
            may = Math.max.apply(ys, ys),
            miy = Math.min.apply(ys, ys),
            //找出近似中间点
            midx = (max+mix) / 2,
            midy = (may+miy) / 2;
        var self = this,
            dis  = 0,
            len = 0,
            prop = 0,
            newData = [];
        this.each(data, function(info, index){
            alp = -self.random(0.1, 1);
            len = min+self.random(offset);
            dis = Math.sqrt(self.getDistance(info, [midx, midy]));
            prop = len/(dis+len);
            newData.push([]);
            var xy = Math.ceil((info[0]-prop*midx)/(1-prop));
            newData[index][0] = xy;
            xy = Math.ceil((info[1]-prop*midy)/(1-prop));
            newData[index][1] = xy;
            newData[index][2] = info[2].concat();
            newData[index][2][3] = alp;
        });
        return newData;
    },

      然后是更新像素点位置,方法是,随机一个前进长度,根据当前点和目标点及移动不长确定下一个移动目标点的位置,如下

    //获取指定长度点目标点位置
    getDestDot : function(data1, data2, length){
        if(data2[1]==data1[1] && data2[0]==data1[0]){
            return data2;
        }
        var xdis = Math.sqrt(this.getDistance(data1, data2)),
            prop = length/xdis;
        x = Math.ceil(prop*(data2[0]-data1[0])) + data1[0];
        y = Math.ceil(prop*(data2[1]-data1[1])) + data1[1];
        return [x, y];
    },

      直到所有的像素全部归位后,设置延迟,再淡出,淡出我就草草处理了,意思意思,效果自己看,源码就不说了。如所有的代码一样可能存在各种兼容性,BUG等等不可预料问题,留言反馈。
      之前1.0版本性能有严重问题,作为反例提供给大家:http://www.mjix.com/code/canvas-text/index1.0.html

25 / 08 / 2014 buling

      之前做了一个单机游戏,由于记录的游戏大小是下载器的大小,现在想还原为安装包大小,被迫从excel中解析大小出来,刚开始使用 xlrd模块,在解析某些excel文件时出现:xlrd.compdoc.CompDocError: Workbook corruption: seen[2] == 4错误信息,被迫改为别的方案,当然,最好的方法使用win32com包调用excel提供的开放接口,刚开始还是报错,错误原因没有记录下来,后来搜索得知是安装的office软件有问题,之前安装的是wps,卸载后安装了微软office2010,测试正常,下面对两个模块读取excel的方法做记录

ipmort xlrd
def test_xlrd():
    xfile = 'xxx/1399864038_0.xls'
    xls = xlrd.open_workbook(xfile)
    table = xls.sheets()[0]
    nrow = table.nrows
    for i in range(nrow):
        row = table.row_values(i)
        #print cell 5 value
        print row[5]

如果上面的方法会出错,请选择win32com模块的方法,如下

def test_win32com():
    xfile = 'F:/wamp/www/softadmin/pcmgr_app/python/bin/xxx/1399864038_0.xls'
    xlApp = win32com.client.Dispatch('Excel.Application')
    xlApp.Visible = False
    xls = xlApp.Workbooks.Open(xfile)
    #index from 1
    table = xls.Worksheets(1)
    #get used info
    info = table.UsedRange
    nrows = info.Rows.Count
    for i in range(nrow):
        cell = table.Rows[i].Cells
        #print cell 5 value
        print cell[5].Value
    #close without save
    xls.Close(SaveChanges=0)

o…

无标签信息 0 条

      额,连续第三天中午写blog了,中午大家休息,抽空来更新一下,最近这几天自己学习了很多。一直以来很想学习游戏中地图的加载,物体碰撞的检测等等。前晚睡觉前看了一下园子,有人发了一篇重力小球的文章,就顺便研究了一下,原文地址:HTML5重力感应小球冲撞动画实现教程,当然我接下来要说的这个和原文的不是一个东东,是小球的碰撞检测。
      相对于很多不规则图形来讲,小球的碰撞检测要相对简单很多,稍微学过物理数学就很容易做速度分解,我参考了这篇文章: 碰撞检测算法优化 ,主要是说一下其中的几个点吧
      1、优化算法。文章说的格子优化算法,把屏幕中的小球分为大小相同的N个格子,碰撞检测只检测,每个格子中的小球是否碰撞,和相邻格子是否有碰撞过程,在检测过程中,应该计算:(i,j),(i-1,j-1),(i,j-1),(i-1,j),(i-1,j+1)这四个,而非对应(i,j)的上下左右四个格子,仔细想想就明白了

      2、动画帧使用requestAnimationFrame,如果没有使用settimeout 1000/60,60是指刷新频率,也可以参考:Javascript高性能动画与页面渲染
      3、在写Too类时,当把类的prototype用{}覆盖后,需要设置 Too.prototype.constructor = Too; 其实理论上不设置也不会有任何问题,也不会影响new时候的构造函数,参考文章: Javascript面向对象编程 以及文章 Why is it necessary to set the prototype constructor?
      废话少说,效果图来,测试地址:http://www.mjix.com/code/canvas-ball.html

无标签信息 0 条
21 / 08 / 2014 buling

      以前吧,一直用python来干这种事情,每次为了能加快速度,写一堆线程代码来做并行。这次用nodejs来实现,怕请求过猛,用了一大堆callback来保证同步,唉,差别啊,爬取是异步,入库还是异步,唉,神伤。结果写完了,测试6个页面并行,一会就悲剧了,对方封了我IP,我那个去,好吧,就不纠结了,代码奉上,看着难受就忍一忍,我也没有使用when或者jquery.deferred啥的,两个表我就不贴了
      话说nodejs确实不错,全异步的感觉,和erlang写个循环需要用递归一样的酷。我觉的最好的地方莫过去,当你处理玩业务需要返回,但还有些事情可以在你返回后完成的,譬如,以前入库完成后,需要发个广播消息,如果是PHP,返回前需要先发送广播需要才能结束,但nodejs就不用,示例代码

app.get('/hello/:query', function(req, res){
  console.log(req.params.query);
  res.send('Hello World');
  //页面返回后需要异步处理别的事件
  setTimeout(function(){
    console.log('do some event');
  }, 1000);
});

是不是…,好,下面是爬去代码

var request    = require('request');
var mysql      = require('mysql');
var crypto     = require('crypto');
var __TIMEOUT__ = 10000;
var URL_CONFIG = [
    ['1', 'http://www.juzimi.com/books?page='],
    ['2', 'http://www.juzimi.com/allarticle/%E7%94%B5%E5%BD%B1?page='],
    ['3', 'http://www.juzimi.com/allarticle/%E5%B0%8F%E8%AF%B4?page='],
    ['4', 'http://www.juzimi.com/allarticle/%E6%95%A3%E6%96%87%E9%9A%8F%E7%AC%94?page='],
    ['5', 'http://www.juzimi.com/allarticle/%E5%8A%A8%E6%BC%AB?page='],
    ['6', 'http://www.juzimi.com/lianxujutaici?page='],
    ['7', 'http://www.juzimi.com/allarticle/%E5%8F%A4%E6%96%87?page=']
];
var URL_HOST = 'http://www.juzimi.com';
var Mysql = {
    config : {
        host     : '127.0.0.1',
        user     : 'root',
        password : '123456',
        database : 'nice_quote',
        charset  : 'utf8'
    },
    connect : function(callback){
        var ins = this.getInstance();
        ins.connect(function(err) {
            if(err) {
                return console.error('error connecting: ' + err.stack);
            }
            console.log('connected as id ' + ins.threadId);
            callback();
        });
    },
    getInstance : function(){
        if(!this._ins){
            this._ins = mysql.createConnection(this.config);
        }
        return this._ins;
    }
};
var getCurrentPage = function(body){
    var page = 0;
    body.replace(/
  • (.*?)<\/li>/ig, function(match, cpage){ page = cpage-1; }); return page; }; var saveDirectory = function(type, info, callback){ var db = Mysql.getInstance(), insertId = 0; var post = { type : type, title : info[1], author : info[2], href : info[0] }; db.query('INSERT IGNORE INTO directory SET ?', post, function(err, result) { if(err){ console.error('error connecting: ' + err.stack); } if(result.insertId===0){ //uniq db.query('SELECT * FROM directory WHERE href=?', [post.href], function(err, result) { if(result){ callback(result[0].id); }else{ callback(0); } }); return ; } callback(result.insertId); }); }; var saveWords = function(did, contents, callback){ var db = Mysql.getInstance(), insertId = 0, md5 = '', post = []; contents.forEach(function(info, index){ md5 = crypto.createHash('md5').update(info).digest('hex'); post.push([did, md5, info]); }); var query = db.query('INSERT INTO info (did, md5, content) VALUES ?', [post], function(err, result) { if(err){ console.error('error connecting: ' + err.stack); } callback(result); }); console.log(query.sql); }; var getInfo = function(url, page, callback){ url += page; console.log(url); request.get({ url : url, timeout : __TIMEOUT__ }, function(error, response, body){ if(!response || !response.statusCode){ callback(-1); return console.log('error:'+error.stack); } if(response.statusCode != 200){ callback(-2); return console.log(response.statusCode); } var cpage = getCurrentPage(body), flag = cpage==page; if(!flag){ //不对的页面 return callback(false); } var rets = []; body.replace(/class=\"xlistju\">([.\s\S]*?)<\/a>/ig, function(match, content){ rets.push(content); }); callback(rets); }); }; /** * //for test * var url = 'http://www.juzimi.com/article/54933?page='; * allInfo(url, 0, function(){ * console.log(url+'-----over!'); * }); */ var allInfo = function(id, url, page, callback){ getInfo(url, page, function(content){ if(content){ if(content==-1){ return allInfo(id, url, page, callback); }else if(content==-2){ callback(); return console.log('error:-1'); } console.log(content); saveWords(id, content, function(){ allInfo(id, url, ++page, callback); }); }else{ //完成 callback(); } }); }; var getList = function(url, page, callback){ //<<<<<<<<<<<<<<<<<<<<<<<<< //if(page>0) return callback(false); url = url + page; request.get({ url : url, timeout : __TIMEOUT__ }, function(error, response, body){ if(!response || !response.statusCode){ callback(-1); return console.log('error:'+error.stack); } if(response.statusCode != 200){ callback(-2); return console.log(response.statusCode); } var cpage = getCurrentPage(body), flag = cpage==page; //console.log(page+'__'+cpage+'__'+flag); if(!flag){ //不对的页面 return callback(false); } var rets = []; body.replace(/\"views-field-tid\">[\s\S]*?(.*?)<\/a>.*?(.*?)<\/a>/ig, function(match, href, bookname, author){ if(author == '喜欢'){ author = ''; } rets.push([href, bookname, author]); }); callback(rets); }); }; var allPages = function(type, list, index, callback){ if(index>=list.length){ return callback(); } var info = list[index]; console.log(type+'__'+info[0] + '__'+info[1]+'__'+info[2]); saveDirectory(type, info, function(id){ allInfo(id, URL_HOST+info[0]+'?page=', 0, function(){ allPages(type, list, ++index, callback); }); }); }; var allList = function(type, url, page, callback){ console.log('curl:['+type+']'+url+page); getList(url, page, function(list){ if(!list){//over return callback(); } if(list==-1){ return allList(type, url, page, callback); }else if(list==-2){ //404 callback(); return console.log('error:-1'); } allPages(type, list, 0, function(){ allList(type, url, ++page, callback); }); }); }; var allSite = function(index){ if(index>=URL_CONFIG.length){ return ; } var info = URL_CONFIG[index]; allList(info[0], info[1], 0, function(){ allSite(++index); }); }; //allSite(0); Mysql.connect(function(){ URL_CONFIG.forEach(function(info, index){ allSite(index); }); // Mysql.getInstance().end(function(err) { // console.log('end mysql!'); // }); });
  •       一看上一篇文章的时间,唉,这就是tx的工作节奏,过去1年基本没有太多需要记录的东西,做了很多运营后台的事情,以及在软件管理V3页面上的优化工作。最近事情稍少一些,闲来学习一下。想想从毕业到现在,刚开始PHP,然后觉得后端很神奇,果断进入后端学习,python做server开发,后来进tx,以前端开发进入,刚开始想在cgi和后端c++上有所成,后觉升级很重要,走专业方向,死攻前端。今年开始尝试了很多前端解决方案,grunt, backbone, seajs, requirejs, nodejs, express等等,这方面还是steve(小碗)牛,也学到了不少。
          由于之前这个岗位在开发中除了使用了extjs,其它方面没有什么特别的积累,所以基本全靠自己摸索学习,从软件管理V3上线,到现在的软件管理,总共修改了很多次,css sprite, grunt, uglify, jshint, cssmin, concat, seajs; js代码基本模块化为多个;由于CSS代码的加载会影响页面呈现,公司的CDN有些问题,所以直接生成在页面中,js的加载也会影响用户的操作,后来真想去jquery,时间问题,最后还是放弃了,现在最新版本,js和首页直接存客户端本地,这样客户端首页就能即刻呈现。
          前不久做了一个微信页面的动画,当时时间很紧急,由于设计给的页面大小不一致没有办法做翻页效果,随意最后的动画也不是很明显,使用了animate.css动画框架,有兴趣自行google或axx;效果地址:http://www.mjix.com/wp-code/wechat/ 相比而言,iphone效果/体验优于android很多。
          最近也在常识sass,编写css代码确实有很多好处,和less、stylus相比,我还是倾向于sass,虽然stylus也是一个不错的选择。sass使用$命名变量,对于phper/jqueryer来说自然比较习惯,再加之混入使用 @mixin声明更明了,在css嵌套中,sass的做法币less好,具体可以查看这篇文章 http://www.oschina.net/question/12_44255
    给一段示例代码

    $dred : darken(#f00, 10%);
    $green : #ff0;
    @mixin test($border:2px){
        border : $border $dred solid;
    }
    .base{position: absolute; top:0; left:0;}
    .test{
        @extend .base;
        @include test(1px);
        background:#ccc;
        .hi{
            color : $green
        }
        $:hover{
            font-weight: bold;
        }
    }
    

    安装一个sass的grunt模块

    grunt.loadNpmTasks('grunt-contrib-sass');
    //建一个sass任务
    sass : {
        dist : {
            options : {
                style : 'expanded'
            },
            files : {
                'sass/test.css' : 'sass/test.scss'
            }
        }
    },
    //建一个watch任务
    watch: {
        files: ['sass/*.scss'],
        tasks: ['sass'],
        options: {
            debounceDelay: 500
        }
    }
    

          其实以前我比较讨厌各种自定义语言,主要是增加学习成本,又不能提升自身对native的学习,当在对这些语言css/js/html等了解的比较熟练的情况下,使用这样的自定义语言可以提高效率,减小维护成本,比如最近看express的jade,这货像python一样的写html。
          之前为了js代码模块化,使用seajs来做开发,其实早在500的时候做配置中心就使用了seajs,但从来没有了解过为何seajs就造出来了还这么流行,最近在infoq上看到一篇文章,里面阐述了seajs和requirejs的区别,文章中引用这里的讨论 http://www.douban.com/note/283566440/ 后来我又看了一个类requirejs的源码,忘了名字了,其实也不复杂。
          backbone,默认需要underscore依赖,那还得去了解一下underscore吧,underscore提供了大量的常用方法,但在一个项目中也不会使用太多,具体可以查询官网API,源码也值得阅读。backbone很适合做单页面的js框架,以前在500的配置中心也是使用了单页面形式,那个时候还没有时间学习backbone,使用hashchange加seajs实现。学习backbone,这确实是一篇不错的教程 https://github.com/the5fire/backbonejs-learning-note
          打开淘宝首页,按F12,查看console栏,它告诉你了一个前端应该了解的大部分技能,如果还有没听过的,那就赶紧。

    无标签信息 0 条