PHP,DDD,CQRS,Event Sourcing,Kubernetes,Docker,Golang

0%

在SNS的网站中,最核心的功能就是Feed功能,Feed就是一条twitter或一条好友动态。该功能面临的挑战是:每天产生成千上万条数据,数据推送的需要实时性等,做网站其实最大的难点就是对海量数据和高并发的处理。本人通过对Twitter和新浪微博架构的一些资料的学习,大致了解了如何实现一个Feed功能。一个Feed功能往往有多种实现方式,最常见的是这3种:推模式、拉模式、推拉结合模式。 推模式: 推就是把自己的发的feed推送到每个粉丝那里,就是一条feed在数据库中存储多份,做法就将feed表按userId分库,对应粉丝Id的库中插一条记录。这种做法的缺点就是数据量大,数据冗余太严重,如一个明星用户有1000万粉丝,那么他发一条feed,就要产生1000万条记录。Feed的推送需要异步队列,队列的好处就是降并发,推送是需要时间的,所以一个明星发了一条feed后,当最后那个粉丝看到这条feed可能已经是几分钟后的事情了。这种模式的优点是用户查看Feed就很容易了,根据userId查询就可以了。这种做法是牺牲大量储存空间来换取网站的查看性能。 拉模式: 拉就是用户要查看动态时就去每个关注者那边找,然后聚合并展现。Feed数据只储存一份,省了很多空间。这种模式在用户量较小的网站就很容易实现,展示只要一条SQL语句。但是当用户多了以后就会遇到问题,比如我关注了2000个用户,而这2000个用户都是活跃用户,每天都会产生很多feed。我查看 feed时就要去2000个关注者那里找最新的几条,合并和按时间排序,每次查看一条查询语句就快把数据库搞得累死,而且合并和排序这些feed计算量太大。拉模式在用户关注人数很多的网站不太适合。 推拉结合: 顾名思义就是两种模式的结合,将两者的优点结合。不活跃的用户(偶偶上线,关注人数又少的僵死用户等)推送的时候就不要推送给他们,省点资源,当他们上线查看时就直接拉,因为他们关注的人比较少,拉也不是很耗性能。 最后,不管采用什么方法实现,少不了异步队列,nosql等工具。比如发表feed的时候就往队列里一扔,前端马上返回,异步慢慢处理,而用户一点也察觉不出来。Nosql缓存,比如一些计数(关注数、粉丝数神马的)直接用redis、TT等储存,还有feed列表可以存储在memcached或redis 中,redis的list功能很适合这种情形,但是一些大网站还不敢这么做。 以上借鉴于新浪微博架构PPT。

1、匿名函数

函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途。匿名函数:就是没有函数名的函数。

1.1 函数的定义,首先简单介绍一下函数的定义,大致可分为三种方式

第一种:这也是最常规的一种

function double(x){
return 2 * x;
}

第二种:这种方法使用了Function构造函数,把参数列表和函数体都作为字符串,很不方便,不建议使用。

var double = new Function(‘x’, ‘return 2 * x;’);

第三种:

var double = function(x) { return 2* x; }

注意“=”右边的函数就是一个匿名函数,创造完毕函数后,又将该函数赋给了变量square。

1.2 匿名函数的创建

第一种方式:就是上面所讲的定义square函数,这也是最常用的方式之一。 第二种方式:

(function(x, y){
alert(x + y);
})(2, 3);

这里创建了一个匿名函数(在第一个括号内),第二个括号用于调用该匿名函数,并传入参数。

2、闭包

闭包的英文单词是closure,这是JavaScript中非常重要的一部分知识,因为使用闭包可以大大减少我们的代码量,使我们的代码看上去更加清晰等等,总之功能十分强大。 闭包的含义:闭包说白了就是函数的嵌套,内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕(这点涉及JavaScript作用域链)。

示例一

function checkClosure(){
var str = ‘rain-man’;
setTimeout(
function(){ alert(str); } //这是一个匿名函数
, 2000);
}
checkClosure();

这个例子看上去十分的简单,仔细分析下它的执行过程还是有许多知识点的:checkClosure函数的执行是瞬间的(也许用时只是0.00001毫秒),在checkClosure的函数体内创建了一个变量str,在checkClosure执行完毕之后str并没有被释放,这是因为setTimeout内的匿名函数存在这对str的引用。待到2秒后函数体内的匿名函数被执行完毕,str才被释放。

示例二,优化代码

function forTimeout(x, y){
alert(x + y);
}
function delay(x , y , time){
setTimeout(‘forTimeout(‘ + x + ‘,’ + y + ‘)’ , time);
}
/**
* 上面的delay函数十分难以阅读,也不容易编写,但如果使用闭包就可以让代码更加清晰
* function delay(x , y , time){
* setTimeout(
* function(){
* forTimeout(x , y)
* }
* , time);
* }
*/

3、举例

匿名函数最大的用途是创建闭包(这是JavaScript语言的特性之一),并且还可以构建命名空间,以减少全局变量的使用。

示例三:

var oEvent = {};
(function(){
var addEvent = function(){ /代码的实现省略了/ };
function removeEvent(){}
oEvent.addEvent = addEvent;
oEvent.removeEvent = removeEvent;
})();

在这段代码中函数addEvent和removeEvent都是局部变量,但我们可以通过全局变量oEvent使用它,这就大大减少了全局变量的使用,增强了网页的安全性。 我们要想使用此段代码:oEvent.addEvent(document.getElementById(‘box’) , ‘click’ , function(){});

示例四:

var rainman = (function(x , y){
return x + y;
})(2 , 3);
/**
* 也可以写成下面的形式,因为第一个括号只是帮助我们阅读,但是不推荐使用下面这种书写格式。
* var rainman = function(x , y){
* return x + y;
* }(2 , 3);
*/

在这里我们创建了一个变量rainman,并通过直接调用匿名函数初始化为5,这种小技巧有时十分实用。

示例五:

var outer = null;
(function(){
var one = 1;
function inner (){
one += 1;
alert(one);
}
outer = inner;
})();
outer(); //2
outer(); //3
outer(); //4

这段代码中的变量one是一个局部变量(因为它被定义在一个函数之内),因此外部是不可以访问的。但是这里我们创建了inner函数,inner函数是可以访问变量one的;又将全局变量outer引用了inner,所以三次调用outer会弹出递增的结果。

4、注意

4.1 闭包允许内层函数引用父函数中的变量,但是该变量是最终值

示例六:

/**
*
*


    *
  • one

  • *
  • two

  • *
  • three

  • *
  • one

  • *

*/
var lists = document.getElementsByTagName(‘li’);
for(var i = 0 , len = lists.length ; i < len ; i++){
lists[ i ].onmouseover = function(){
alert(i);
};
}

你会发现当鼠标移过每一个<li&rt;元素时,总是弹出4,而不是我们期待的元素下标。这是为什么呢?注意事项里已经讲了(最终值)。显然这种解释过于简单,当mouseover事件调用监听函数时,首先在匿名函数( function(){ alert(i); })内部查找是否定义了 i,结果是没有定义;因此它会向上查找,查找结果是已经定义了,并且i的值是4(循环后的i值);所以,最终每次弹出的都是4。 解决方法一:

var lists = document.getElementsByTagName(‘li’);
for(var i = 0 , len = lists.length ; i < len ; i++){
(function(index){
lists[ index ].onmouseover = function(){
alert(index);
};
})(i);
}

解决方法二:

var lists = document.getElementsByTagName(‘li’);
for(var i = 0, len = lists.length; i < len; i++){
lists[ i ].$$index = i; //通过在Dom元素上绑定$$index属性记录下标
lists[ i ].onmouseover = function(){
alert(this.$$index);
};
}

解决方法三:

function eventListener(list, index){
list.onmouseover = function(){
alert(index);
};
}
var lists = document.getElementsByTagName(‘li’);
for(var i = 0 , len = lists.length ; i < len ; i++){
eventListener(lists[ i ] , i);
}

phper刚入门的思考以下问题: 修改过别人的开源代码没? oop熟悉吗,class自省ok? mvc知道吗?设计过吗? framework你知道几个?代码研究过没? js库用过几个? sql掌握得怎样了? phper 一两年的思考以下问题: php安全你研究透了? 分布式应用你懂吗? 缓存你懂得多少? soap你也用过了? unix,linux系统你能拿几分,简单shell你也ok了? mysql你真懂了吗? sql优化你也在行了? js你写吗?水平怎样了?………… 3年以上的: c语言懂吗? php 内核研究过没? 写php拓展没问题吗? webservice ok吗? 你有带队的能力吗?…………