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> 接下來(lái)我們就是用管道和鏈?zhǔn)絹?lái)壓縮和解壓文件。
創(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。
接下來(lái),讓我們來(lái)解壓該文件,創(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è)簡(jiǎn)單的模塊系統(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è)模塊非常簡(jiǎn)單,如下我們創(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ì)象。
接下來(lái)我們就來(lái)創(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方法極其簡(jiǎn)單,但是內(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) 語(yǔ)句執(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類似,舉例來(lái)說(shuō),你可以這樣做:

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

以上代碼中,我們把 say 函數(shù)作為execute函數(shù)的第一個(gè)變量進(jìn)行了傳遞。這里返回的不是 say 的返回值,而是 say 本身!
這樣一來(lái), say 就變成了execute 中的本地變量 someFunction ,execute可以通過調(diào)用 someFunction() (帶括號(hào)的形式)來(lái)使用 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è)賮?lái)看看我們簡(jiǎn)約而不簡(jiǎn)單的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ù)來(lái)執(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模塊來(lái)解析POST請(qǐng)求體中的參數(shù).
現(xiàn)在我們來(lái)給onRequest()函數(shù)加上一些邏輯,用來(lái)找出瀏覽器請(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路徑來(lái)區(qū)別不同請(qǐng)求了--這使我們得以使用路由(還未完成)來(lái)將請(qǐng)求以URL路徑為基準(zhǔn)映射到處理程序上。
在我們所要構(gòu)建的應(yīng)用中,這意味著來(lái)自/start和/upload的請(qǐng)求可以使用不同的代碼來(lái)處理。稍后我們將看到這些內(nèi)容是如何整合到一起的。
現(xiàn)在我們可以來(lái)編寫路由了,建立一個(gè)名為 router.js 的文件,添加以下內(nèi)容:

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

如你所見,這段代碼什么也沒干,不過對(duì)于現(xiàn)在來(lái)說(shuō)這是應(yīng)該的。在添加更多的邏輯以前,我們先來(lái)看看如何把路由和服務(wù)器整合起來(lái)。
我們的服務(wù)器應(yīng)當(dāng)知道路由的存在并加以有效利用。我們當(dāng)然可以通過硬編碼的方式將這一依賴項(xiàng)綁定到服務(wù)器上,但是其它語(yǔ)言的編程經(jīng)驗(yàn)告訴我們這會(huì)是一件非常痛苦的事,因此我們將使用依賴注入的方式較松散地添加路由模塊。
首先,我們來(lái)擴(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)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,013評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,146評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,534評(píng)論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,767評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,318評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,074評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,258評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,486評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評(píng)論 1 290
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,993評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,234評(píng)論 2 375

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

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