Node.js 實戰(zhàn)_1 Node 基礎(chǔ)

Node 基礎(chǔ)

JavaScript 是編程語言,而 Node.js 是執(zhí)行環(huán)境涮总。

Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運行環(huán)境(runtime)窿祥。

Node.js 特性:事件驅(qū)動解总、異步 API凯亮、非阻塞 I/O较曼。

Node.js 是專為數(shù)據(jù)密集型實時程序(DITR)設(shè)計的糕珊。

Node.js 通過事件輪詢(event loop)來實現(xiàn)非阻塞I/O網(wǎng)絡(luò)的調(diào)用动分,而事件輪詢是單向運行的先入先出隊列。

ES2015

ECMAScript 2015 是 ECMAScript 標(biāo)準(zhǔn)的第6個版本红选,所以有時候也被稱為 ES6澜公,一般簡寫為 ES2015。

Node 支持的 ES2015 特性匯總

ES5 之前需要用 prototype 對象來創(chuàng)建類似于類的結(jié)構(gòu):

function User() {
  // 構(gòu)造器
}

User.prototype.method = function () {
  // 方法
}

ES6 版本支持類:

class User {
  constructor() {}
  method() {}
}

const 和 let 解決作用域問題

在 ES5 中喇肋,所有的變量都是用 var 創(chuàng)建的坟乾。

應(yīng)該用 const 還是 let

在決定是用 const 還是用 let 時蝶防,幾乎都可以用 const甚侣。因為你的大部分代碼都是在用你自己的類實例、對象常量或不會變的值间学,所以大部分情況下都可以用 const殷费。即便是有可修改屬性的對象,也是可以用 const 聲明的低葫,因為 const 的意思是引用是只讀的详羡,而不是值是不可變的

原生的 promise 和生成器支持

生成器能把異步 I/O 變成同步編程風(fēng)格嘿悬。

模版字符串

用反引號(`)定義模版字符串

// ES5 中实柠,字符串常量不支持插值,也不支持跨行善涨。
// 舊的方法
var a = 1;
console.log('一共有 ' + a + ' 個雞蛋窒盐!');

// 模版字符串語法
var a = 1;
console.log(`一共有 ${a} 個雞蛋!`);

箭頭函數(shù)

舊版語法:

const http = require('http');
const port = 8080;

const server = http.createServer(function (req, res) {
  res.end('Hello, world.');
});

server.listen(port, function () {
  console.log('Server listening on: http://localhost:%s', port);
});

箭頭函數(shù)語法:

const http = require('http');
const port = 8080;

const server = http.createServer((req, res) => {
  res.end('Hello, world.');
});

server.listen(port, () => {
  console.log('Server listening on: http://localhost:%s', port);
});

Node.js 架構(gòu)

Node.js 的軟件棧
Node.js 架構(gòu)

說明:

  • libuv 是提供快速钢拧、跨平臺蟹漓、非阻塞 I/O 的本地庫;
  • V8 負(fù)責(zé) JavaScript 代碼的解釋和執(zhí)行娶靡,它可以將 JavaScript 直接編譯為機(jī)器碼牧牢;
  • C++ 綁定層可以將 libuv 和 V8 結(jié)合起來。

Node 的使用場景

Node 程序主要可以分成三種類型:Web 應(yīng)用程序、命令行工具塔鳍、和后臺程序伯铣、桌面程序。

Node 的使用場景
From @itying.com

Node 功能的組織及重用

Node 模塊打包代碼是為了重用轮纫,但它們不會改變?nèi)肿饔糜颉?/p>

Node 的模塊系統(tǒng)避免了對全局作用域的污染腔寡,從而也就避免了命名沖突,并簡化了代碼的重用掌唾。

模塊即可以是一個文件放前,也可以是包含一個或多個文件的目錄(默認(rèn)模塊入口為 index.js 文件)。

currency.js

自定義模塊糯彬,在該文件中添加兩個貨幣轉(zhuǎn)換函數(shù):
方法:通過設(shè)定 exports 對象的屬性來指明要暴露的函數(shù)或變量凭语。

// 私有變量,外界無法訪問到撩扒。
var candaianDollar = 0.91;

function roundTwoDecimals(amount) {
    return Math.round(amount * 100) / 100;
}

// canadianToUS() 函數(shù)設(shè)定在 exports 模塊中似扔,所以引入這個模塊的代碼可以使用它。
exports.canadianToUS = function (canadian) {
    return roundTwoDecimals(canadian * candaianDollar);
}

// USToCanadian() 函數(shù)也設(shè)定在 exports 模塊中搓谆。
exports.USToCanadian = function (us) {
    return roundTwoDecimals(us / candaianDollar);
}

test-currency.js

引入模塊

// require() 函數(shù)是一個同步I/O函數(shù)炒辉,一般在文件頂端引入。
// 相對路徑 ./ 表示當(dāng)前同一目錄下泉手。
const currency = require('./currency');

// 使用 currency 模塊的 canadianToUS() 函數(shù)
console.log(currency.canadianToUS(50));

// 使用 currency 模塊的 USToCanadian() 函數(shù)
console.log(currency.USToCanadian(30));

用 module.exports 微調(diào)模塊的創(chuàng)建

  • 如果只需要從模塊中得到一個函數(shù)黔寇,那么從 require 中返回一個函數(shù)的代碼比返回一個對象的代碼更優(yōu)雅。

  • 不能用任何其他對象斩萌、函數(shù)或者變量給 exports 賦值缝裤。

    我的理解:可以把函數(shù)或者對象設(shè)置為 exports 的屬性(exports.function = {...}),但是不能把函數(shù)或者對象賦值(exports = function)給 exports颊郎。

  • module.exports 可以對外提供單個變量倘是、函數(shù)或者對象。

  • 如果你創(chuàng)建了一個既有 exports 又有 module.exports 的模塊袭艺,那它會返回 module.exports,而 exports 會被忽略叨粘。

exports 與 module.exports

最終在程序里導(dǎo)出的是module.exports猾编。exports只是對module.exports的一個全局引用,最初被定義為一個可以添加屬性的空對象升敲。所以exports.myFunc只是module.exports.myFunc的簡寫答倡。

所以,如果把exports設(shè)定為別的驴党,就打破了module.exports和exports之間的引用關(guān)系瘪撇。

  • 根據(jù)需要使用 exportsmodule.exports 可以將功能組織成模塊,規(guī)避掉程序腳本一直增長產(chǎn)生的弊端。

用 node_modules 重用模塊

Node 查找模塊的步驟
  • 用環(huán)境變量 NODE_PATH 可以改變 Node 模塊的默認(rèn)路徑倔既。

注意事項

  1. 如果模塊是目錄恕曲,在模塊目錄中定義模塊的文件必須被命名為 index.js,除非你在這個目錄下一個叫package.json 的文件里特別指明渤涌。
  2. Node 能把模塊作為對象緩存起來佩谣。Node 加載模塊的順序:緩存模塊>核心模塊>當(dāng)前目錄模塊>node_modules模塊。
  3. 有些常用的 Node 核心模塊在 Node 初始化時就被加載緩存起來了实蓬,所以加載速度相對也會更快茸俭。

異步編程技術(shù)

Node 中兩種響應(yīng)邏輯管理方式:回調(diào)和事件監(jiān)聽。

  • 回調(diào):適用于一次性異步邏輯安皱。

  • 事件發(fā)射器:把異步邏輯跟一個概念實體關(guān)聯(lián)起來调鬓,可以通過監(jiān)聽器輕松管理。

  • 流程控制:可以管理異步任務(wù)的執(zhí)行順序酌伊,串行執(zhí)行或者并行執(zhí)行腾窝。

1. 用回調(diào)處理一次性事件

回調(diào)是一個函數(shù),它被當(dāng)做參數(shù)傳給異步函數(shù)腺晾,它描述了異步操作完成之后要做什么燕锥。

HTML示例

title.json

JSON 文件會被格式化成一個包含文章標(biāo)題的字符串?dāng)?shù)組。

[
    "Kazakhstan is a huge country...what goes on there?",
    "This weather is making me craaazy",
    "My neighbor sort of howls at night"
]

template.html

HTML 模版文件悯蝉,% 會被替換為博客文章的標(biāo)題归形。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Page Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <h1>Latest Posts</h1>
    <ul><li>%</li></ul>
</html>

blog_recent.js

功能如下:

  • 異步獲取存放在 JSON 文件中的文章的標(biāo)題;
  • 異步獲取簡單的 HTML 模版鼻由;
  • 把標(biāo)題組裝在 HTML 模版中暇榴;
  • 把 HTML 頁面發(fā)送給用戶。
// 獲取 JSON 文件中的標(biāo)題蕉世,并渲染 Web 頁面
'use strict';

const http = require('http');
const fs = require('fs');
const path = require('path');

// 創(chuàng)建 HTTP 服務(wù)器蔼紧,并用回調(diào)定義響應(yīng)邏輯
http.createServer(function (req, res) { 
    if (req.url == '/') {
        // 讀取 JSON 文件并用回調(diào)定義如何處理其中的內(nèi)容
        // fs.readFile() 直接讀取文件的相對路徑會報錯,這里用 path 拼接狠轻。
        fs.readFile(path.join(__dirname, './titles.json'), function (err, data) {
            // 如果出錯奸例,輸入錯誤日志,并給客戶端返回錯誤
            if (err) { 
                console.error(err);
                res.end('Server Error: Read JSON File Error');
            }else {
                // 從 JSON 文本中解析數(shù)據(jù)
                var titles = JSON.parse(data.toString());

                // 讀取 HTML 模版向楼,并在加載完成后使用回調(diào)
                fs.readFile(path.join(__dirname, './template.html'), function (err, data) {
                    if (err) {
                        console.error(err);
                        res.end('Server Error: Read html Error');
                    }else {
                        var tmp1 = data.toString();

                        // 組裝 HTML 頁面以顯示博客標(biāo)題
                        var html = tmp1.replace('%', titles.join('</li><li>'));
                        res.writeHead(200, {'Content-Type': 'text/html'});
                        // 將 HTML 頁面發(fā)送給用戶
                        res.end(html);
                    }
                });
            }
        });
    }
}).listen(8000, '127.0.0.1');

這個示例嵌入了三層回調(diào):

http.createServer(function (req, res) { 
    fs.readFile(path.join(__dirname, './titles.json'), function (err, data) {
        fs.readFile(path.join(__dirname, './template.html'), function (err, data) {
        });
    });
});

優(yōu)化方式:創(chuàng)建中間函數(shù)以減少嵌套(也可以理解為:將代碼模塊化)查吊。

就是把步驟中的單一功能抽象為單獨的中間函數(shù)。

...

優(yōu)化方式:通過盡早返回減少嵌套湖蜕。

const http = require('http');
const fs = require('fs');
const path = require('path');

const server = http.createServer(function (req, res) {
    getTitles(res);
}).listen(8000, "127.0.0.1");

function getTitles(res) {
    fs.readFile(path.join(__dirname, './titles.json'), function (err, data) {
        // 不再創(chuàng)建 else 分支逻卖,而是直接return,因為如果出錯的話昭抒,也沒有必要繼續(xù)執(zhí)行這個函數(shù)了评也。
        if (err) return hadError(err, res);
        getTemplate(JSON.parse(data.toString()), res);
    });
}

function getTemplate(titles, res) {
    fs.readFile(path.join(__dirname, './template.html'), function (err, data) {
        if (err) return hadError(err, res);
        formatHtml(titles, data.toString(), res);
    });
}

function formatHtml(titles, tmp1, res) {
    var html = tmp1.replace('%', titles.join('</li><li>'));
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end(html);
}

function hadError(err, res) {
    console.error(err);
    res.end('Server Error');
}

Node 的異步回調(diào)慣例

Node 中的大多數(shù)內(nèi)置模塊在使用回調(diào)時都會帶兩個參數(shù):第一個用來放可能會發(fā)生的錯誤炼杖,第二個放結(jié)果。錯誤參數(shù)經(jīng)常被縮寫為 err盗迟。

下面是這個常用的函數(shù)簽名的典型示例:

var fs = require('fs');
fs.readFile('./titles.json', function (err, data) {
    if (err) throw err;
    // do something with data if no error has occurred
})

2. 用事件發(fā)射器處理重復(fù)性事件

事件發(fā)射器會觸發(fā)事件坤邪,并且在那些事件被觸發(fā)時能處理它們。

事件是通過監(jiān)聽器進(jìn)行處理的诈乒。

監(jiān)聽器是跟事件相關(guān)聯(lián)的罩扇、當(dāng)有事件出現(xiàn)時就會被觸發(fā)的回調(diào)函數(shù)。

const net = require('net');
var server = net.createServer(function (socket) {
    // 當(dāng)有客戶端連接上來時怕磨,它就會創(chuàng)建一個socket喂饥。
    // 用 on 方法添加監(jiān)聽器響應(yīng) data 事件。
    socket.on('data', function (data) {
        socket.write(data);
    });

    // once 方法肠鲫,data 事件只是在第一次會被處理
    socket.once('data', function (data) {
        socket.write(data);
    })
}).listen(8888);

用 Node 內(nèi)置的事件模版創(chuàng)建自己的事件發(fā)射器:

// 定義一個channel事件發(fā)射器员帮,帶有一個監(jiān)聽器,可以向加入頻道的人做出響應(yīng)导饲。
var EventEmitter = require('events').EventEmitter;
var channel = new EventEmitter();
// 用on(或者用比較長的addListener)方法給事件發(fā)射器添加了監(jiān)聽器:
channel.on('join', function () {
    console.log('Welcome!');
})

// 用emit函數(shù)發(fā)射這個事件
channel.emit('join');

錯誤處理

創(chuàng)建發(fā)出 error 類型事件的事件發(fā)射器捞高,而不是直接拋出錯誤。

// 創(chuàng)建一個錯誤監(jiān)聽器渣锦,將被發(fā)出的錯誤輸出到控制臺中:
const events = require('events');
var myEmitter = new events.EventEmitter();
myEmitter.on('error', function (err) {
    console.log('ERROR: ' + err.message);
});
myEmitter.emit('error', new Error('Something is wrong.'));

異步開發(fā)的難題

創(chuàng)建異步程序時硝岗,必須密切關(guān)注程序的執(zhí)行流程、程序的執(zhí)行狀態(tài)...

// 示例:作用域是如何導(dǎo)致 bug 出現(xiàn)的:
function asyncFunction(callback) {
  // 200ms 后袋毙,執(zhí)行回調(diào)函數(shù)
  setTimeout(callback, 200);
}
let color = 'blue';
asyncFunction(() => {
  console.log(`The color is ${color}`);
});
color = 'green';

// 輸出結(jié)果:
// [Running] node "/Users/andy/Desktop/node/test_async.js"
// The color is green

用匿名函數(shù)保留全局變量的值:

// JavaScript 編程技巧:用閉包控制程序的狀態(tài)
function asyncFunction(callbback) {
    setTimeout(callbback, 200);
}
var conlor = 'blue';

// 將 color 的值傳給匿名函數(shù)
// color 變成了匿名函數(shù)的參數(shù)型檀,也就是這個匿名函數(shù)內(nèi)部的本地變量,
// 當(dāng)匿名函數(shù)外面的color值發(fā)生變化時听盖,本地版的color不會受影響胀溺。
(function(color) {
    asyncFunction(function() {
        console.log('The color is' + color);
    })
})(color);

color = 'green';

MDN web docs: JavaScript 閉包

異步邏輯的順序化

流程控制:讓一組異步任務(wù)按照順序執(zhí)行。串行/并行皆看。

需要一個接著一個做的任務(wù)叫做串行任務(wù)仓坞。

不需要一個接著一個做的任務(wù)叫做并行任務(wù)

串行任務(wù)與并行任務(wù)

實現(xiàn)串行化流程控制

使用回調(diào)讓幾個異步任務(wù)順序執(zhí)行:

setTimeout(function() {
    console.log('1');
    setTimeout(function() {
        console.log('2');
        setTimeout(function() {
            console.log('3');
        }, 100); // 任務(wù)3腰吟,花費 0.1 秒
    }, 500); // 任務(wù)2无埃,花費 0.5 秒
}, 1000); // 任務(wù)1,花費 1 秒

第三方模塊:Nimble:這個模塊官網(wǎng)上顯示7年沒更新了??????毛雇,而且現(xiàn)在流行用 Promise 或者 async 來實現(xiàn)录语。

// 《Node.js 實戰(zhàn)(第二版)》Async 示例:
const async = require('async');

// 給 Async 一個函數(shù)數(shù)組,讓它一個接一個地執(zhí)行
async.series([
  callback => {
    setTimeout(() => {
      console.log('I execute first.');
      callback();
    }, 1000);
  },
  callback => {
    setTimeout(() => {
      console.log('I execute next.');
      callback();
    }, 500);
  },
  callback => {
    setTimeout(() => {
      console.log('I execute last.');
      callback();
    }, 100);
  },
]);

// 執(zhí)行結(jié)果:
// [Running] node "/Users/andy/Desktop/node/test_async.js"
// I execute first.
// I execute next.
// I execute last.

串行化流程控制的工作機(jī)制:

為了用串行化流程控制讓幾個異步任務(wù)按順序執(zhí)行禾乘,需要先把這些任務(wù)按預(yù)期的執(zhí)行順序放到一個數(shù)組中。

這個數(shù)組將起到隊列的作用:完成一個任務(wù)后按順序從數(shù)組中取出下一個虽缕。

Demo示例:實現(xiàn)串行化流程控制始藕。

實現(xiàn)并行化流程控制

為了讓異步任務(wù)并行執(zhí)行蒲稳,仍然是要把任務(wù)放到數(shù)組中,但任務(wù)的存放順序無關(guān)緊要伍派。每個任務(wù)都應(yīng)該調(diào)用處理器函數(shù)增加已完成任務(wù)的計數(shù)值江耀。當(dāng)所有任務(wù)都完成后,處理器函數(shù)應(yīng)該執(zhí)行后續(xù)的邏輯诉植。

'use strict';

const async = require('async');
const exec = require('child_process').exec;

// 輔助函數(shù):下載指定版本的 Node.js 源碼
function downloadNodeVersion(version, destination, callback) {
  const url = `http://nodejs.org/dist/v${version}/node-v${version}.tar.gz`;
  const filepath = `${destination}/${version}.tgz`;
  exec(`curl ${url} > ${filepath}`, callback);
}

// 串行執(zhí)行兩個任務(wù):
// 任務(wù)一:并行下載兩個版本的源碼祥国;
// 任務(wù)二:將下載好的版本歸檔到一個新文件中。
// 用串行化流程控制保證在文件下載完成之前不會做歸檔處理晾腔。
async.series([
  callback => {
    // 并行下載
    async.parallel([
      callback => {
        console.log('Downloading Node V4.4.7...');
        downloadNodeVersion('4.4.7', '/tmp', callback);
      },
      callback => {
        console.log('Downloading Node v6.3.0');
        downloadNodeVersion('6.3.0', '/tmp', callback);
      },
    ], callback);
  },
  callback => {
    console.log('Creating archive of download files ...');
    exec(
      'tar cvf node_distros.tar /tmp/4.4.7.tgz /tmp/6.3.0.tgz',
      err => {
        if (err) throw err;
        console.log('All down!');
        callback();
      }
    );
  },
], (err, results) => {
  if (err) throw err;
  console.log(results);
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舌稀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子灼擂,更是在濱河造成了極大的恐慌壁查,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剔应,死亡現(xiàn)場離奇詭異睡腿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)峻贮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門席怪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人纤控,你說我怎么就攤上這事挂捻。” “怎么了嚼黔?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵细层,是天一觀的道長。 經(jīng)常有香客問我唬涧,道長疫赎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任碎节,我火速辦了婚禮捧搞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狮荔。我一直安慰自己胎撇,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布殖氏。 她就那樣靜靜地躺著晚树,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雅采。 梳的紋絲不亂的頭發(fā)上爵憎,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天慨亲,我揣著相機(jī)與錄音,去河邊找鬼宝鼓。 笑死刑棵,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的愚铡。 我是一名探鬼主播蛉签,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼沥寥!你這毒婦竟也來了碍舍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤营曼,失蹤者是張志新(化名)和其女友劉穎乒验,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蒂阱,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡锻全,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了录煤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鳄厌。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖妈踊,靈堂內(nèi)的尸體忽然破棺而出了嚎,到底是詐尸還是另有隱情,我是刑警寧澤廊营,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布歪泳,位于F島的核電站,受9級特大地震影響露筒,放射性物質(zhì)發(fā)生泄漏呐伞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一慎式、第九天 我趴在偏房一處隱蔽的房頂上張望伶氢。 院中可真熱鬧,春花似錦瘪吏、人聲如沸癣防。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蕾盯。三九已至,卻和暖如春蓝丙,著一層夾襖步出監(jiān)牢的瞬間级遭,已是汗流浹背香嗓。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留装畅,地道東北人。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓沧烈,卻偏偏與公主長得像掠兄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锌雀,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359

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

  • topics: 1.The Node.js philosophy 2.The reactor pattern 3....
    宮若石閱讀 1,088評論 0 1
  • Node.js第一天 1. 初識Node.js 1.1 Node.js是什么 Node.js? is a Java...
    再見天才閱讀 4,741評論 1 24
  • # 模塊機(jī)制 node采用模塊化結(jié)構(gòu)蚂夕,按照CommonJS規(guī)范定義和使用模塊,模塊與文件是一一對應(yīng)關(guān)系腋逆,即加載一個...
    RichRand閱讀 2,510評論 0 3
  • Node.js是目前非承鲭梗火熱的技術(shù),但是它的誕生經(jīng)歷卻很奇特惩歉。 眾所周知等脂,在Netscape設(shè)計出JavaScri...
    w_zhuan閱讀 3,617評論 2 41
  • 工作當(dāng)中經(jīng)常會有會議,會議的主持人要提前的做許多的準(zhǔn)備工作撑蚌,要能夠很好的把握好對話上遥,因為會議主要是通過語言來傳遞信...
    向陽的石頭閱讀 323評論 0 0