阻塞与非阻塞IO

阻塞与非阻塞IO


Node中,你需要对回调函数如何修改当前内存中的变量(状态)特别小心。

1
2
3
4
5
6
7
var books = ["红楼梦", "三国演义"];
function serveBooks(){
//给客户端返回的HTML代码
var html = '<b>' + books.join('</b><br><b>')+'</b>';
books = [];
return html;
}

等价的PHP代码

1
2
3
4
5
6
$books = array('harry', 'dollars');
function serveBooks(){
$html = '<b>'.join($books, '</b><br><b>').'</b>';
$books = array();
return $html;
}
APACHE

PHP PHP
THREAD THREAD

REQUEST REQUEST

NODE.JS
THREAD

REQUEST REQUEST REQUEST

node.js只有借助child_process 才能生成新的process

采用事件轮询意味 甚么 呢?
Node会先注册事件, 随后,不停的询问内核,这些事情是否已经分发

了不起的node.js学习笔记

chapter 2 JavaScript概览

介绍

js是基于原型,面向对象, 弱类型的的动态脚本语言。

Javascript基础

  • 类型:

    • 基本类型包括number, boolean, string, null 及 undefined
    • 复杂类型包括array, function 及 object

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      var a = 5;
      var b = 5;
      b = a;
      a; // => 5
      b; //=> 6
      var a = ['hello', 'world', 1]; //array
      var b = a;
      b[0] = 'bye';
      a[0]; //=> 'bye'
      b[0]; //= >'bye'
    • 类型的困惑(在js中判断变量值的类型并非易事)
      你可以用两种方式来创建字符串

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      var a = 'woot';
      var b = new String('woot')
      a + b; //=> 'woot woot'
      //要对这两个变量使用typeof和instanceof操作符,things go fun.
      typeof a; //'string'
      typeof b; //'object'
      a instanceof String; //false
      b instanceof String; //true
      //事实上, 这两个变量值绝对都是字符串
      a.substr == b.substr; //true
      a == b; //true
      a === b; //false 考虑类型是否相同了
      //考虑有此差异,建议通过直观方式进行定义,避免使用new
      //特定值会被判定为false: null, undefined, ' ', 0
      var a = 0;
      if(a){
      //will not execute
      }
      a == false; //true
      a === false; //false
      //值得注意的是:
      typeof null == 'object'; //很不幸,结果为true
      //数组也不例外
      typeof [] == 'object'; // true;
  • 函数
    javascript 中函数最重要。它们都属于一等函数:可以作为引用存储在变量中,随后可以像其他对象一样,进行传递:
    1
    2
    var a = function(){}
    console.log(a); //将函数作为参数传递

Javascript 中所有的函数都可以进行命名。有一点很重要,就是要区分函数名和变量名。

1
2
3
var a = function a () {
'function' == typeof a; //true
};

  • THIS, FUNCTION#CALL, FUNCTION#APPLY
    下面代码中函数被调用时, this的值是全局对象。在浏览器中,就是window对象。

    1
    2
    3
    4
    function a() {
    window == this; //true
    };
    a();

调用以下函数时,使用.call 和.apply 方法可以改变this值:

1
2
3
4
function a() {
this.a == 'b'; // true
}
a.call({a: 'b'});

call 和 apply 区别在于 call 接受参数列表, 而apply接受一个参数数组

1
2
3
4
5
6
function a(b, c){
b == 'first'; //true;
c == 'second'; //true
};
a.call({a: 'b'}, 'first', 'second');
a.apply({a: 'b'}, ['first', 'second']);

  • 函数的参数数量
    函数有一个很有意思的属性—参数数量, 该属性指明函数声明时可接受的参数数量。在javascript中,该属性名叫length。
    1
    2
    var a = function(a, b, c);
    a.length == 3; //true

尽管者在浏览器端很少使用, 但是, 他对我们非常重要, 因为一些流行的node框架通过此属性来根据不同的参数个数提供不同功能的。

  • 闭包
    在javascript中, 每次函数调用时, 新的作用域就会产生。
    在某个作用域中定义的变量只能在该作用域或其内部的作用域(该作用域中定义的作用域)中才能访问到:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var a = 5;
    function woot(){
    a == 5; //false;
    var a = 6;
    function test(){
    a == 6; //true
    };
    test();
    };
    woot();

自执行函数是一种机制, 通过者中机制声明和调用一个匿名函数, 能够达到仅定义一个新作用域的作用。

1
2
3
var a = 3;
(function(){var a = 5;})();
a == 3; //true;

自执行函数对声明私有变量很有用的, 这样可以让私有变量不被其他代码所访问。


  • javascript中没有class关键词, 类只能通过函数来定义:
    1
    function Animal(){}

要给所有的Animal的实例定义函数, 可以通过prototype属性来完成:

1
2
3
Animal.prototype.eat = function(food){
//eat method
};

这里值得一提的时, 在prototype的函数内部, this并非像普通函数那样指向global对象, 而是指向通过该创建的实例对象:

1
2
3
4
5
6
7
8
function Animal(name) {
this.name = name;
}
Animal.prototype.getName(){
return this.name;
};
var animal = new Animal('tobi');
a.getName == 'tobi'; //true

  • 继承
    javascript有基于原型的继承的特定。通常,你可以通过以下方式来模拟类型继承。
    定义一个要继承自Animal的构造器。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function Ferret(){};
    //要定义继承链, 首先创建一个Animal对象, 然后将其赋值给ferret.prototype.
    //实现继承
    Ferret.prototype = new Animal();
    //随后可以为子类定义属性和方法:
    Ferret.prototype.type = 'domestic';
    //还可以通过prototype来重写和调用父类函数
    Ferret.prototype.eat = function(food){
    Animal.prototype.eat.call(this, foot);//调用父类函数
    //ferrte特有的逻辑写在这里
    }

慕课网
92C8DD3E-A2FC-418C-9DDB-C8ED9C8C4022.png

1
2
3
4
5
6
var animal = new Animal();
animal instanceof Animal //true
animal instanceof Ferret; // false
var ferret = new Ferret();
ferret instanceof Animal; //true
ferret instanceof Ferret; //true

这项技术是同类方案中最好的, 不会改变instanceof操作符的结果。

它的不足: 声明继承的时候创建的对象总要进行初始化(Ferret.prototype=new Animal),这种方式不好。一种解决办法就是在构造器中添加判断条件:

1
2
3
4
5
function Animal(a){
if(false !== a) return;
//初始化
}
Ferret.prototype = new Animal(false);

另外一个办法就是在定义一个新的空的构造器, 并重写它的原型:

1
2
3
4
5
6
function Animal(){
//constructor stuff
};
function f() {};
f.prototype = Animal.prototype;
Ferret.prototype = new f;

v8 提供了更为简洁的解决方案

  • TRY{} CATCH{}
    try/catch 允许进行异常捕获。下述代码会抛出异常

    var a = 5;
    a[]
    当函数抛出错误时, 代码就停止执行:

    1
    2
    3
    4
    function () {
    throw new Error('hi');
    console.log('hi'); //这里永远不会被执行到
    }

若使用try/catch则可以进行错误处理, 并让代码继续执行下去:

1
2
3
4
5
6
7
8
9
function () {
var a = 5;
try {
a[];
}catch(e){
e instanceof Error; //true
}
console.log('you get here!')
}

  • v8中的javascript

    -OBJECT#KEYS
    要想获取下述对象的键值(a and c):

    1
    var a = {a: 'b', c: 'd'};

通常会使用如下迭代方式:

1
for(var i in a) {}

通过对键值进行迭代, 可以将它们收集到一个数组中。不过, 如果采用如下方式对prototype进行扩展:

1
object.prototype.c = 'd';

为了避免迭代中获取c可以用hasOwnProperty来进行检查

1
2
3
for(var i in a){
if(a.hasOwnProperty(i)){}
}

在v8中, 要获取对象的自由键, 还有更简单的方法:

1
2
var a = {a: 'b', c: 'd'};
Object.keys(a);

  • ARRAY#ISARRAY
    对数组使用typeof操作符会返回object, 然而大部分情况下, 我们要检查数组是否真的是数组。
    1
    2
    3
    4
    Array.isArray(new Array) //true
    Array.isArray([]) //true
    Array.isArray(null) //false
    Array.isArray(arguments) //false
  • 数组方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //要遍历数组, 可以使用forEach($.each(jquery中))
    [1, 2, 3].forEach(function(v){
    console.log(v);
    })
    //要过滤数组中的元素
    [1, 2, 3].filter(function(v){
    return v < 3;
    });
    //要改变数组中每个元素的值,可以使用map
    [1, 2,3 ].map(function(v){
    return v * 2;
    }); //[2, 4, 6]
  • 字符串方法
    要移除字符串首末的空格, 可以使用:

    1
    '  hello '.trim();
  • JSON
    v8 提供了JSON.stringfy 和JSON.parse的方法来对JSON数据进行解码和编码

    1
    2
    var obj = JSON.parse('{"a": "b"}');
    obj.a == 'b'; //true
  • FUNCTION#BIND
    .bind 允许改变this的引用

    1
    2
    3
    4
    5
    function a(){
    this.hello == "world"; //true
    };
    var b = a.bind({hello, "world"});
    b();
  • FUNCTION#NAME
    V8还支持非标准的函数属性名:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var a = function woot() {};
    a.name == "woot"; //true
    //该属性用于v8内部的堆栈追踪。当错误抛出时, v8会显示一个堆栈追踪的信息, 会告诉你是哪个函数用导致了错误的发生。
    var woot = function() {throw new Error();};
    woot();
    //Error:
    // at [object context]: 1:32
    //v8无法为函数的引用指派名字。然而,如果对函数进行了命名,v8就能在堆栈追踪中将函数名显示出来:
    var woot = function buggy(){throw new Error();}
    woot();
    //Error
    //at buggy ([object context]: 1: 34)
  • PROTO(继承)
    proto“使得定义继承链变得更加容易

    1
    2
    3
    4
    5
    function Animal() {}
    function Ferret() {}
    Ferret.prototype.__proto__ = Animal.prototype;
    //这是一个非常有用的特性:
    //免去如下工作: 1.借助中间构造器, 2, 借助OOP工具类库。
  • 存取器
    你可以通过调用方法来定义属性, 访问属性就使用defineGetter, 设置属性就使用defineSetter.
    比如, 为Date对象定义一个ago属性, 返回以自然语言描述的日期间隔。
    很多时候, 特别在软件中, 想用自然语言来描述日期距离某个特定时间点的时间间隔。比如: “某事件发生在三秒前”, 这种表达,要远比“某件事情发生在x年x月x日”, 这种表达更容易理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
//基于John的prettyDate
Date.prototype.__defineGetter___('ago', function(){
var diff = (new Date()).getTime() - this.getTime()) / 1000)
var day_diff = Math.floor(diff / 86400);
return day_diff == 0 && (diff < 60 && "just now" ||
diff < 120 && "1 minute ago" ||
diff < 3600 && Math.floor(diff/60) + "minutes ago" ||
diff<7200 && "1 hour ago"||
diff < 86400 && Math.floor((diff/3600) + "hours ago") ||
day_diff == 1 && "Yesterday"||
day_diff < 7 && "day_diff" + " days ago"||
Math.ceil(day_diff/ 7 + "weeks ago";
});

然后简单的访问ago属性即可

var a = new Date(‘09/18/1991’);
a.ago;

算法导论-1

算法

算法设计的若干通用策略


  1. 穷举搜索

    • 直截了当的试遍所有解
    • 局限: 效率低下

      幻方问题
      幻方

      3*3的方格中填9个数,使其横,纵,斜的和均相等。
      很显然,有9!种组合。让计算机去遍历他们一遍吧。当问题规模变大的时候,算死你。
      其实,要证明公共的和是15,然后中间放5。


  1. 回溯法

  2. 减而治之

  3. 分而治之

  4. 变而治之
  5. 贪心法
  6. 迭代改进
  7. 动态规划