NodeJs 入門到放棄 — 入門基本介紹(一)
碼文不易啊,轉載請帶上本文鏈接呀,感謝感謝 //www.cnblogs.com/echoyya/p/14450905.html
NodeJs 介紹
Node.js 就是運行在服務端的 JavaScript。是基於Chrome V8 引擎的JavaScript 運行環境
,簡單理解就是一個可以讓JavaScript脫離瀏覽器,執行的平台,並對JavaScript功能進行了增強(文件系統,模塊,包,操作系統API,網絡通訊,數據庫操作等)
與JavaScript的區別:Node.js 是運行環境,JavaScript是一門編程語言
NodeJs 運行使用
-
安裝:下載地址
-
REPL模式:(Read-Evaluate-Print-Loop),即
交互式命令行解析器
,可以直接在命令行輸入node
,啟動Node 的終端,直接編寫NodeJs代碼,適合用來測試和學習-
讀取 – 讀取用戶輸入,解析輸入的 Javascript 數據結構並存儲在內存中。
-
執行 – 執行輸入的數據結構
-
打印 – 輸出結果
-
循環 – 循環操作以上步驟直到用戶兩次按下 ctrl-c 按鈕退出。
-
-
運行JS文件:
node XXX.js
模塊化
-
目前有三種流行的模塊化規範:分別是 AMD(異步加載 requirejs),CMD(seajs),
Commonjs(同步加載,只適用於服務端 NodeJs平台)
-
NodeJs採用模塊方式管理和組織代碼,NodeJs所有的功能都存在每個模塊中
模塊組成
模塊:一個具有特定功能的文件就是一個模塊,模塊之間相互獨立,同時也可以相互共享數據,需要暴露數據和引入操作
/**
* NodeJs模塊組成:
* 所有用戶編寫的代碼都在模塊中,模塊就是文件(函數)
* 該函數有五個參數:
* exports: 暴露對象,可以將模塊中的數據暴露給引用模塊
* require: 引入模塊,用於在A模塊中引入B模塊,並將B模塊暴露的數據賦值給變量
* module: 模塊對象,包含了當前模塊的所有信息
* __filename: 當前模塊的文件名
* __dirname: 當前模塊所在的路徑
*/
// arguments 屬性只能在函數內部使用,因此說明模塊就是函數
console.log(arguments.callee.toString()); // 打印出函數體本身
exports.username = 'Echoyya'
// console.log(arguments); // 可以將參數分別打印
require 函數
作用:在當前模塊加載另一模塊,不同類型的模塊,引入模塊時也有一些差異
模塊分類:
-
自定義模塊:開發者自己編寫的功能文件即為自定義模塊
-
若子模塊沒有暴露數據時,返回空對象
-
自定義模塊必須加
./
,否則nodejs查找模塊默認在node_modules
目錄中查找 -
主模塊:整個項目的啟動模塊,有且僅有一個,對其他模塊進行整合調度
-
// hello.js
var obj = require('./test')
console.log(obj); // {}
// test.js
console.log('Echoyya');
-
第三方模塊:第三方程序員或公司開發的模塊,先安裝再使用,npm 安裝,require 使用
-
系統模塊:nodejs開發團隊提供的功能模塊 ,直接引入使用即可,無需安裝
模塊初始化:當一個模塊被多次引入時,只執行一次,將暴露對象exports直接寫入緩存,後續就直接讀取緩存
exports 導出對象
作用:是當前模塊的導出對象,用於導出模塊公有方法和屬性,其他模塊通過require函數加載使用
exports.屬性 = 值
exports.方法 = 函數
// test.js 暴露屬性和方法
var username = 'Echoyya'
function showName(){
console.log('test模塊:showName方法被調用');
console.log(module.exports === exports); // true
}
exports.name = username
exports.show = showName
// hello.js 加載調用
var obj = require('./test')
obj.show()
-
exports對象 和 module.exports對象,指同一個內存空間, module.exports對象才是真正的暴露對象
-
exports對象 是 module.exports對象的引用
,不能改變指向,只能添加屬性和方法,若直接改變exports 的指向,則返回空對象 -
console.log(module.exports === exports); // true
-
若想直接暴露對應的showName函數,可以改變module.exports的指向,module.exports=showName
module 模塊對象
module.exports :暴露對象,exports對象只是對其的引用
// 常用語法:
module.exports.屬性 = 值
module.exports.方法 = 函數
module.exports = 對象或函數
以下內容作為了解即可:
-
module.id:模塊ID,模塊名稱
-
module.parent:模塊的父級
-
module.filename:模塊的文件名和路徑
-
module.children:子模塊列表
-
module.paths:模塊查找路徑,默認查找當前目錄下的node_modules,若沒有則向上查找,直至根目錄,如果另外配置了NODE_PATH環境變量,也會去查找
npm和package.json文件
npm:(Node Package Manager)是基於Nodejs的包管理工具,能解決NodeJS代碼部署上的很多問題
-
允許用戶從NPM服務器下載別人編寫的第三方包到本地使用。
-
允許用戶將自己編寫的包或命令行程序上傳到NPM服務器供別人使用。
-
新版的nodejs已經集成了npm,可以通過輸入 “npm -v” 來測試是否成功安裝
package.json:以JSON格式描述nodejs項目的包描述文件,創建語法:npm init
或 npm init -y
(默認全部yes)
Nodejs 作用域
Nodejs中一個文件即是一個模塊,由於nodejs在執行時會將用戶編寫的所有代碼都封裝在函數中,因此模塊中用戶使用var聲明的變量或函數都是局部的只能在該模塊中使用。
共享數據給其他模塊使用的方法:
-
暴露對象:module.exports,文章上述有詳細的描述
-
全局對象
:nodejs中沒有window對象,但是有global對象
(盡量少用),可以把共享數據掛載到global對象上,以供其他模塊使用,使用時global關鍵字可以省略
Nodejs 異步編程實現的三種方式
1. 回調函數
Node.js 異步編程的直接體現就是回調,Node 使用了大量的回調函數並且Node 所有 API 都支持回調函數。這就大大提高了 Node.js 的性能,可以處理大量的並發請求。
回調函數:又稱回調,將A函數的引用地址作為參數傳遞給B函數(調用者),B函數在執行過程中根據時機或條件決定是否調用A函數,A函數就是回調函數,一般作為函數的最後一個參數出現。
異步一定有回調函數
,但是回調函數不一定是異步
// 異步一定有回調函數
setTimeout(function () {
console.log('1');
}, 0);
console.log(2) // 輸出結果 2 1
// 回調函數不一定是異步
console.log(1);
var arr = ['a','b','c']
arr.forEach(function(v){
console.log(v);
})
console.log(3); // 輸出結果 1 a b c 3 即為同步
2. 事件
var http = require('http')
var server = http.createServer()
server.on('request',function(req, res){
res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"}) // 設置編碼
res.write('<h1>訪問nodejs服務</h1>')
res.end()
})
server.listen(80,function(){
console.log('服務器運行.....');
})
3. Promise 對象
promise是ES6中新增的對象,用於對異步的操作進行消息的傳遞,由於異步的返回結果時間順序並不可控,使用promise就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。解決了以往的回調地獄現象。並提供統一的接口,使得控制異步操作更加容易。
promise有三種狀態:pending
(進行中)、resolved
(已成功)和rejected
(已失敗),對象的狀態不受外界影響。
Promise
對象的狀態改變,只有兩種可能:從pending
變為resolved
和從pending
變為rejected
。一旦發生,狀態就凝固不會再變。任何時候都可以得到這個結果。
Promise 提供的API遠不止這些,還有許多強大的接口,更多具體用法,請參考阮老師的 [ECMAScript 6 入門]
var fs = require('fs')
function asyncReadFile(url){
return new Promise(function(resolved, rejected){
fs.readFile(url,function(err,data){
if(err) {
rejected(err)
}else{
resolved(data.toString())
}
})
})
}
var p1 = asyncReadFile('./file1.txt')
var p2 = asyncReadFile('./file2.txt')
// 異步的返回結果時間順序並不可控,p2可能會先執行完畢,
p1.then(function(value){
console.log('p1',value);
},function(err){
console.log(err);
})
p2.then(function(value){
console.log('p2',value);
},function(err){
console.log(err);
})
// Promise.all()用於將多個Promise實例,包裝成一個新的Promise實例
// 數組格式傳入多個Promise實例可以執行順序
//[p1,p2]
Promise.all([p1,p2]).then(function(datas){
console.log('[p1,p2]',datas);
},function(errs){
console.log(errs);
})
// [p2,p1]
Promise.all([p2,p1]).then(function(datas){
console.log('[p2,p1]',datas);
},function(errs){
console.log(errs);
})