Node.js<四>

Node.js Stream(流)

Stream 是一個(gè)抽象接口悼瘾,Node 中有很多對(duì)象實(shí)現(xiàn)了這個(gè)接口捆憎。例如握恳,對(duì)http 服務(wù)器發(fā)起請(qǐng)求的request 對(duì)象就是一個(gè) Stream挖帘,還有stdout(標(biāo)準(zhǔn)輸出)完丽。
Node.js,Stream 有四種流類型:
<li>Readable - 可讀操作拇舀。
<li>Writable - 可寫操作逻族。
<li>Duplex - 可讀可寫操作.
<li>Transform - 操作被寫入數(shù)據(jù),然后讀出結(jié)果骄崩。
所有的 Stream 對(duì)象都是 EventEmitter 的實(shí)例聘鳞。常用的事件有:
<li>data - 當(dāng)有數(shù)據(jù)可讀時(shí)觸發(fā)。
<li>end - 沒有更多的數(shù)據(jù)可讀時(shí)觸發(fā)要拂。
<li>error - 在接收和寫入過程中發(fā)生錯(cuò)誤時(shí)觸發(fā)抠璃。
<li>finish - 所有數(shù)據(jù)已被寫入到底層系統(tǒng)時(shí)觸發(fā)。

從流中讀取數(shù)據(jù)

創(chuàng)建 input.txt 文件脱惰,內(nèi)容如下:

hello world!

創(chuàng)建 main.js 文件, 代碼如下:

var fs = require("fs");
var data = '';
// 創(chuàng)建可讀流
var readerStream = fs.createReadStream('input.txt');
// 設(shè)置編碼為 utf8鸡典。
readerStream.setEncoding('UTF8');
// 處理流事件 --> data, end, and error
readerStream.on('data', function(chunk) {
   data += chunk;
});
readerStream.on('end',function(){
   console.log(data);
});
readerStream.on('error', function(err){
   console.log(err.stack);
});
console.log("程序執(zhí)行完畢");

寫入流

創(chuàng)建 main.js 文件, 代碼如下:

var fs = require('fs');
var data = "hello world!!!"
// 創(chuàng)建一個(gè)可以寫入的流,寫入到文件 output.txt 中
var writerStream = fs.createWriteStream('output.txt');
// 使用 utf8 編碼寫入數(shù)據(jù)
writerStream.write(data,'UTF8');
// 標(biāo)記文件末尾
writerStream.end();
// 處理流事件 --> finish, end, and error
writerStream.on('finish',function{
  console.log('寫入完成!');
});
writerStream.on('error',function(err){
  console.log(err.stack);
});
console.log('程序執(zhí)行完畢');

以上程序會(huì)將 data 變量的數(shù)據(jù)寫入到 output.txt 文件中枪芒。代碼執(zhí)行結(jié)果如下:



查看 output.txt 文件的內(nèi)容:


管道流

管道提供了一個(gè)輸出流到輸入流的機(jī)制彻况。通常我們用于從一個(gè)流中獲取數(shù)據(jù)并將數(shù)據(jù)傳遞到另外一個(gè)流中。



如上面的圖片所示舅踪,我們把文件比作裝水的桶纽甘,而水就是文件里的內(nèi)容,我們用一根管子(pipe)連接兩個(gè)桶使得水從一個(gè)桶流入另一個(gè)桶抽碌,這樣就慢慢的實(shí)現(xiàn)了大文件的復(fù)制過程悍赢。
以下實(shí)例我們通過讀取一個(gè)文件內(nèi)容并將內(nèi)容寫入到另外一個(gè)文件中决瞳。
設(shè)置 input.txt 文件內(nèi)容如下:

hello world
管道流操作實(shí)例

創(chuàng)建 main.js 文件, 代碼如下:

var fs = require('fs');
//創(chuàng)建一個(gè)輸入流
var readerStream = fs.createReadStream('input.txt');
//創(chuàng)建一個(gè)輸出流
var writerStream = fs.createWriteStream('output.txt');
// 管道讀寫操作
// 讀取 input.txt 文件內(nèi)容,并將內(nèi)容寫入到 output.txt 文件中
readerStream.pipe(writerStream);
console.log('程序執(zhí)行完畢');

代碼執(zhí)行結(jié)果如下:



查看 output.txt 文件的內(nèi)容:


鏈?zhǔn)搅?/h1>

鏈?zhǔn)绞峭ㄟ^連接輸出流到另外一個(gè)流并創(chuàng)建多個(gè)對(duì)個(gè)流操作鏈的機(jī)制左权。鏈?zhǔn)搅饕话阌糜诠艿啦僮鳌?br> 接下來我們就是用管道和鏈?zhǔn)絹韷嚎s和解壓文件皮胡。
創(chuàng)建 compress.js 文件, 代碼如下:

var fs = require("fs");
var zlib = require('zlib');
// 壓縮 input.txt 文件為 input.txt.gz
fs.createReadStream('input.txt')
  .pipe(zlib.createGzip())
  .pipe(fs.createWriteStream('input.txt.gz'));
console.log("文件壓縮完成。");

代碼執(zhí)行結(jié)果如下:



執(zhí)行完以上操作后赏迟,我們可以看到當(dāng)前目錄下生成了 input.txt 的壓縮文件 input.txt.gz屡贺。
接下來,讓我們來解壓該文件锌杀,創(chuàng)建 decompress.js 文件甩栈,代碼如下:

var fs = require('fs');
var zip = require('zlib');
fs.createReadStream('input.txt.gz').pipe(zip.createGunzip()).pipe(fs.createWriteStream('input.txt'));
console.log('文件解壓完成');

代碼執(zhí)行結(jié)果如下:


Node.js模塊系統(tǒng)

為了讓Node.js的文件可以相互調(diào)用,Node.js提供了一個(gè)簡單的模塊系統(tǒng)糕再。
模塊是Node.js 應(yīng)用程序的基本組成部分量没,文件和模塊是一一對(duì)應(yīng)的。換言之突想,一個(gè) Node.js 文件就是一個(gè)模塊殴蹄,這個(gè)文件可能是JavaScript 代碼、JSON 或者編譯過的C/C++ 擴(kuò)展猾担。

創(chuàng)建模塊

在 Node.js 中袭灯,創(chuàng)建一個(gè)模塊非常簡單,如下我們創(chuàng)建一個(gè) 'main.js' 文件垒探,代碼如下:

var hello = require('./hello');
hello.world();

以上實(shí)例中妓蛮,代碼 require('./hello') 引入了當(dāng)前目錄下的hello.js文件(./ 為當(dāng)前目錄,node.js默認(rèn)后綴為js)圾叼。
Node.js 提供了exports 和 require 兩個(gè)對(duì)象蛤克,其中 exports 是模塊公開的接口,require 用于從外部獲取一個(gè)模塊的接口夷蚊,即所獲取模塊的 exports 對(duì)象构挤。
接下來我們就來創(chuàng)建hello.js文件,代碼如下:

exports.world = function() {
  console.log('Hello World');
}

在以上示例中惕鼓,hello.js 通過 exports 對(duì)象把 world 作為模塊的訪問接口筋现,在 main.js 中通過 require('./hello') 加載這個(gè)模塊,然后就可以直接訪 問 hello.js 中 exports 對(duì)象的成員函數(shù)了箱歧。
有時(shí)候我們只是想把一個(gè)對(duì)象封裝到模塊中矾飞,格式如下:

module.exports = function() {
  // ...
}

例如:

//hello.js 
var Hello = function() { 
    var name; 
    this.setName = function(thyName) { 
        name = thyName; 
    }; 
    this.sayHello = function() { 
        console.log('Hello ' + name); 
    }; 
}; 
module.exports = Hello;

這樣就可以直接獲得這個(gè)對(duì)象了:

//main.js 
var Hello = require('./hello'); 
hello = new Hello(); 
hello.setName('HB'); 
hello.sayHello(); 

模塊接口的唯一變化是使用 module.exports = Hello 代替了exports.world = function(){}。 在外部引用該模塊時(shí)呀邢,其接口對(duì)象就是要輸出的 Hello 對(duì)象本身洒沦,而不是原先的 exports。

服務(wù)端的模塊放在哪里

也許你已經(jīng)注意到价淌,我們已經(jīng)在代碼中使用了模塊了申眼。像這樣:

var http = require("http");
...
http.createServer(...);

Node.js中自帶了一個(gè)叫做"http"的模塊瞒津,我們?cè)谖覀兊拇a中請(qǐng)求它并把返回值賦給一個(gè)本地變量。
這把我們的本地變量變成了一個(gè)擁有所有 http 模塊所提供的公共方法的對(duì)象括尸。
Node.js 的 require方法中的文件查找策略如下:
由于Node.js中存在4類模塊(原生模塊和3種文件模塊)巷蚪,盡管require方法極其簡單,但是內(nèi)部的加載卻是十分復(fù)雜的濒翻,其加載優(yōu)先級(jí)也各自不同屁柏。如下圖所示:


從文件模塊緩存中加載

盡管原生模塊與文件模塊的優(yōu)先級(jí)不同,但是都不會(huì)優(yōu)先于從文件模塊的緩存中加載已經(jīng)存在的模塊肴焊。

從原生模塊加載

原生模塊的優(yōu)先級(jí)僅次于文件模塊緩存的優(yōu)先級(jí)前联。require方法在解析文件名之后功戚,優(yōu)先檢查模塊是否在原生模塊列表中娶眷。以http模塊為例,盡管在目錄下存在一個(gè)http/http.js/http.node/http.json文件啸臀,require("http")都不會(huì)從這些文件中加載届宠,而是從原生模塊中加載。
原生模塊也有一個(gè)緩存區(qū)乘粒,同樣也是優(yōu)先從緩存區(qū)加載豌注。如果緩存區(qū)沒有被加載過,則調(diào)用原生模塊的加載方式進(jìn)行加載和執(zhí)行灯萍。

從文件加載

當(dāng)文件模塊緩存中不存在轧铁,而且不是原生模塊的時(shí)候,Node.js會(huì)解析require方法傳入的參數(shù)旦棉,并從文件系統(tǒng)中加載實(shí)際的文件齿风,加載過程中的包裝和編譯細(xì)節(jié)在前一節(jié)中已經(jīng)介紹過,這里我們將詳細(xì)描述查找文件模塊的過程绑洛,其中救斑,也有一些細(xì)節(jié)值得知曉。
require方法接受以下幾種參數(shù)的傳遞:
<li>http真屯、fs脸候、path等,原生模塊绑蔫。
<li>./mod或../mod运沦,相對(duì)路徑的文件模塊。
<li>/pathtomodule/mod配深,絕對(duì)路徑的文件模塊携添。
<li>mod,非原生模塊的文件模塊凉馆。
在路徑 Y 下執(zhí)行 require(X) 語句執(zhí)行順序:

1. 如果 X 是內(nèi)置模塊
   a. 返回內(nèi)置模塊
   b. 停止執(zhí)行
2. 如果 X 以 '/' 開頭
   a. 設(shè)置 Y 為文件根路徑
3. 如果 X 以 './' 或 '/' or '../' 開頭
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
4. LOAD_NODE_MODULES(X, dirname(Y))
5. 拋出異常 "not found"
LOAD_AS_FILE(X)
1. 如果 X 是一個(gè)文件, 將 X 作為 JavaScript 文本載入并停止執(zhí)行薪寓。
2. 如果 X.js 是一個(gè)文件, 將 X.js 作為 JavaScript 文本載入并停止執(zhí)行亡资。
3. 如果 X.json 是一個(gè)文件, 解析 X.json 為 JavaScript 對(duì)象并停止執(zhí)行。
4. 如果 X.node 是一個(gè)文件, 將 X.node 作為二進(jìn)制插件載入并停止執(zhí)行向叉。
LOAD_INDEX(X)
1. 如果 X/index.js 是一個(gè)文件,  將 X/index.js 作為 JavaScript 文本載入并停止執(zhí)行锥腻。
2. 如果 X/index.json 是一個(gè)文件, 解析 X/index.json 為 JavaScript 對(duì)象并停止執(zhí)行。
3. 如果 X/index.node 是一個(gè)文件,  將 X/index.node 作為二進(jìn)制插件載入并停止執(zhí)行母谎。
LOAD_AS_DIRECTORY(X)
1. 如果 X/package.json 是一個(gè)文件,
   a. 解析 X/package.json, 并查找 "main" 字段瘦黑。
   b. let M = X + (json main 字段)
   c. LOAD_AS_FILE(M)
   d. LOAD_INDEX(M)
2. LOAD_INDEX(X)
LOAD_NODE_MODULES(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
   a. LOAD_AS_FILE(DIR/X)
   b. LOAD_AS_DIRECTORY(DIR/X)
NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
   a. if PARTS[I] = "node_modules" CONTINUE
   b. DIR = path join(PARTS[0 .. I] + "node_modules")
   c. DIRS = DIRS + DIR
   d. let I = I - 1
5. return DIRS

Node.js 函數(shù)

在JavaScript中,一個(gè)函數(shù)可以作為另一個(gè)函數(shù)的參數(shù)奇唤。我們可以先定義一個(gè)函數(shù)幸斥,然后傳遞,也可以在傳遞參數(shù)的地方直接定義函數(shù)咬扇。
Node.js中函數(shù)的使用與Javascript類似甲葬,舉例來說,你可以這樣做:

function say(word) {
  console.log(word);
}
function execute(someFunction, value) {
  someFunction(value);
}
execute(say, "Hello");

以上代碼中懈贺,我們把 say 函數(shù)作為execute函數(shù)的第一個(gè)變量進(jìn)行了傳遞经窖。這里返回的不是 say 的返回值,而是 say 本身梭灿!
這樣一來画侣, say 就變成了execute 中的本地變量 someFunction ,execute可以通過調(diào)用 someFunction() (帶括號(hào)的形式)來使用 say 函數(shù)堡妒。
當(dāng)然配乱,因?yàn)?say 有一個(gè)變量, execute 在調(diào)用 someFunction 時(shí)可以傳遞這樣一個(gè)變量皮迟。

匿名函數(shù)

我們可以把一個(gè)函數(shù)作為變量傳遞搬泥。但是我們不一定要繞這個(gè)"先定義,再傳遞"的圈子万栅,我們可以直接在另一個(gè)函數(shù)的括號(hào)中定義和傳遞這個(gè)函數(shù):

function execute(someFunction,value){
  someFunction(value);
}
execute(function(world){console.log(world)},'hello');

我們?cè)?execute 接受第一個(gè)參數(shù)的地方直接定義了我們準(zhǔn)備傳遞給 execute 的函數(shù)佑钾。
用這種方式,我們甚至不用給這個(gè)函數(shù)起名字烦粒,這也是為什么它被叫做匿名函數(shù) 休溶。

函數(shù)傳遞是如何讓HTTP服務(wù)器工作的

帶著這些知識(shí),我們?cè)賮砜纯次覀兒喖s而不簡單的HTTP服務(wù)器:

var http = require("http");
http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}).listen(8888);

現(xiàn)在它看上去應(yīng)該清晰了很多:我們向 createServer 函數(shù)傳遞了一個(gè)匿名函數(shù)扰她。
用這樣的代碼也可以達(dá)到同樣的目的:

var http = require("http");
function onRequest(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}
http.createServer(onRequest).listen(8888);

Node.js 路由

我們要為路由提供請(qǐng)求的URL和其他需要的GET及POST參數(shù)兽掰,隨后路由需要根據(jù)這些數(shù)據(jù)來執(zhí)行相應(yīng)的代碼。
因此徒役,我們需要查看HTTP請(qǐng)求孽尽,從中提取出請(qǐng)求的URL以及GET/POST參數(shù)。這一功能應(yīng)當(dāng)屬于路由還是服務(wù)器(甚至作為一個(gè)模塊自身的功能)確實(shí)值得探討忧勿,但這里暫定其為我們的HTTP服務(wù)器的功能杉女。
我們需要的所有數(shù)據(jù)都會(huì)包含在request對(duì)象中瞻讽,該對(duì)象作為onRequest()回調(diào)函數(shù)的第一個(gè)參數(shù)傳遞。但是為了解析這些數(shù)據(jù)熏挎,我們需要額外的Node.JS模塊速勇,它們分別是url和querystring模塊。

 url.parse(string).query
                                           |
           url.parse(string).pathname      |
                       |                   |
                       |                   |
                     ------ -------------------
http://localhost:8888/start?foo=bar&hello=world
                                ---       -----
                                 |          |
                                 |          |
              querystring.parse(queryString)["foo"]    |
                                            |
                         querystring.parse(queryString)["hello"]

當(dāng)然我們也可以用querystring模塊來解析POST請(qǐng)求體中的參數(shù).
現(xiàn)在我們來給onRequest()函數(shù)加上一些邏輯坎拐,用來找出瀏覽器請(qǐng)求的URL路徑:

var http = require("http");
var url = require("url");
var start = function() {
  function onRequest(request, response) {
    var pathname = url.parse(request.url).pathname;
    console.log("Request for " + pathname + " received.");
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
  }
  http.createServer(onRequest).listen(8888);
  console.log("Server has started.");
}
exports.start = start;

好了烦磁,我們的應(yīng)用現(xiàn)在可以通過請(qǐng)求的URL路徑來區(qū)別不同請(qǐng)求了--這使我們得以使用路由(還未完成)來將請(qǐng)求以URL路徑為基準(zhǔn)映射到處理程序上。
在我們所要構(gòu)建的應(yīng)用中哼勇,這意味著來自/start和/upload的請(qǐng)求可以使用不同的代碼來處理都伪。稍后我們將看到這些內(nèi)容是如何整合到一起的。
現(xiàn)在我們可以來編寫路由了积担,建立一個(gè)名為 router.js 的文件陨晶,添加以下內(nèi)容:

function route(pathname) {
  console.log("About to route a request for " + pathname);
}
exports.route = route;

如你所見,這段代碼什么也沒干磅轻,不過對(duì)于現(xiàn)在來說這是應(yīng)該的珍逸。在添加更多的邏輯以前逐虚,我們先來看看如何把路由和服務(wù)器整合起來聋溜。
我們的服務(wù)器應(yīng)當(dāng)知道路由的存在并加以有效利用。我們當(dāng)然可以通過硬編碼的方式將這一依賴項(xiàng)綁定到服務(wù)器上叭爱,但是其它語言的編程經(jīng)驗(yàn)告訴我們這會(huì)是一件非常痛苦的事撮躁,因此我們將使用依賴注入的方式較松散地添加路由模塊。
首先买雾,我們來擴(kuò)展一下服務(wù)器的start()函數(shù)把曼,以便將路由函數(shù)作為參數(shù)傳遞過去,server.js 文件代碼如下

var http = require("http");
var url = require("url");
function start(route) {
  function onRequest(request, response) {
    var pathname = url.parse(request.url).pathname;
    console.log("Request for " + pathname + " received.");
    route(pathname);
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
  }
  http.createServer(onRequest).listen(8888);
  console.log("Server has started.");
}
exports.start = start;

同時(shí)漓穿,我們會(huì)相應(yīng)擴(kuò)展index.js嗤军,使得路由函數(shù)可以被注入到服務(wù)器中:

var server = require('./main');
var router = require('./route');
server.start(router.route);

現(xiàn)在啟動(dòng)應(yīng)用(node index.js,始終記得這個(gè)命令行)晃危,隨后請(qǐng)求一個(gè)URL叙赚,你將會(huì)看到應(yīng)用輸出相應(yīng)的信息,這表明我們的HTTP服務(wù)器已經(jīng)在使用路由模塊了僚饭,并會(huì)將請(qǐng)求的路徑傳遞給路由:



瀏覽器訪問 http://127.0.0.1:8888/震叮,輸出結(jié)果如下:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市鳍鸵,隨后出現(xiàn)的幾起案子苇瓣,更是在濱河造成了極大的恐慌,老刑警劉巖偿乖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件击罪,死亡現(xiàn)場離奇詭異哲嘲,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)媳禁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門撤蚊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人损话,你說我怎么就攤上這事侦啸。” “怎么了丧枪?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵光涂,是天一觀的道長。 經(jīng)常有香客問我拧烦,道長忘闻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任恋博,我火速辦了婚禮齐佳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘债沮。我一直安慰自己炼吴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布疫衩。 她就那樣靜靜地躺著硅蹦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪闷煤。 梳的紋絲不亂的頭發(fā)上童芹,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音鲤拿,去河邊找鬼假褪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛近顷,可吹牛的內(nèi)容都是我干的生音。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼幕庐,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼久锥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起异剥,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤瑟由,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體歹苦,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡青伤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了殴瘦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狠角。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蚪腋,靈堂內(nèi)的尸體忽然破棺而出丰歌,到底是詐尸還是另有隱情,我是刑警寧澤屉凯,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布立帖,位于F島的核電站,受9級(jí)特大地震影響悠砚,放射性物質(zhì)發(fā)生泄漏晓勇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一灌旧、第九天 我趴在偏房一處隱蔽的房頂上張望绑咱。 院中可真熱鬧,春花似錦枢泰、人聲如沸描融。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稼稿。三九已至,卻和暖如春讳窟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背敞恋。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工丽啡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人硬猫。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓补箍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親啸蜜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坑雅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • Node.js是目前非常火熱的技術(shù)衬横,但是它的誕生經(jīng)歷卻很奇特裹粤。 眾所周知,在Netscape設(shè)計(jì)出JavaScri...
    w_zhuan閱讀 3,609評(píng)論 2 41
  • 個(gè)人入門學(xué)習(xí)用筆記蜂林、不過多作為參考依據(jù)遥诉。如有錯(cuò)誤歡迎斧正 目錄 簡書好像不支持錨點(diǎn)拇泣、復(fù)制搜索(反正也是寫給我自己看...
    kirito_song閱讀 2,451評(píng)論 1 37
  • topics: 1.The Node.js philosophy 2.The reactor pattern 3....
    宮若石閱讀 1,059評(píng)論 0 1
  • Node.js是目前非常火熱的技術(shù)矮锈,但是它的誕生經(jīng)歷卻很奇特霉翔。 眾所周知,在Netscape設(shè)計(jì)出JavaScri...
    Myselfyan閱讀 4,064評(píng)論 2 58
  • 剛收到一個(gè)表苞笨,密密麻麻都是記錄债朵,我要的是數(shù)據(jù)分析,OK??很多人知道要做工作記錄瀑凝,但不知道這些記錄沉淀下來的數(shù)據(jù)的...
    穆穆瑾閱讀 288評(píng)論 0 0