欲練此功,必先自宮;javascript
沒必要自宮,亦可練成;html
兄臺仍是好好修煉此功吧!保持一個清醒的頭腦,你將駕馭這匹野馬!!!前端
—— 致讀者vue
知識就像海洋同樣,永遠也學不完,可是不斷精益求精是一種態度,是對新事物的一種持續保持瞻望的態度,希望你在學習的樂園裏不斷完善己身,不斷修煉,等待破繭成蝶。java
#
##
####
—— 致開發者 node
好的書寫風格可以讓讀者的思路清晰,一樣能讓人有繼續閱讀的興趣,希望你能按照此風格繼續完善本書籍。git
單線程只是針對主進程,I/O操做系統底層進行多線程調度。也就是它僅僅起一個監聽做用。es6
### 舉個栗子叭 場景:飯店 情節:人流量高併發 BOSS的策略:僱傭多名廚師,只僱傭一個服務員,當多名顧客點餐的時候,服務員告訴廚師,作菜,上菜。
單線程並非只開一個進程。github
### Node.js中的cluster(集羣)模塊 官方介紹:單個 Node.js 實例運行在單個線程中。 爲了充分利用多核系統,有時須要啓用一組 Node.js 進程去處理負載任務。 Demo: const cluster = require('cluster'); const http = require('http'); const numCPUs = require('os').cpus().length; if (cluster.isMaster) { console.log(`主進程 ${process.pid} 正在運行`); // 衍生工做進程。 for (let i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', (worker, code, signal) => { console.log(`工做進程 ${worker.process.pid} 已退出`); }); } else { // 工做進程能夠共享任何 TCP 鏈接。 // 在本例子中,共享的是 HTTP 服務器。 http.createServer((req, res) => { res.writeHead(200); res.end('你好世界\n'); }).listen(8000); console.log(`工做進程 ${process.pid} 已啓動`); }
CommonJSweb
module
變量表明模塊自己。module.exports
屬性表明模塊對外接口。
ModuleDemo.js
console.log('this is a module'); const testVar = 100; function test () { console.log(testVar); } module.exports.testVar = testVar; module.exports.testFn = test;
使用模塊之require規則
- /
表示絕對路徑,./
表示相對於當前文件的路徑。
- 支持js
、json
、node
拓展名
- 不寫路徑則認爲是build-in
模塊或者各級node-modules
內的第三方模塊
CommonJS Use Module
const modu = require('ModuleDemo.js'); console.log(modu.testVar); console.log(modu.test);
require特性
引用系統模塊
const fs = require('fs'); const result = fs.readFile('fs.js',( err, data) => { if (err) { return err; } console.log(data); }); console.log(result);
引用第三方模塊
npm i chalk -S
const chalk = require('chalk');
{ function(exports,require,module,__filename,__dirname) { // code } }
簡而言之,exports就是module.exports的一個簡寫,也就是一個引用,別名。
exports = { a: 1, b: 2, test: 123 } //這樣是錯誤的 exports.test = 100; //只能添加屬性,可是不能修改其指向 //固然 module.exports = { a:1, b:2, test:123, } //這樣是沒問題的
global.test = 200;
/** * argv * argv0 * execArgv * execPath */ const {argv, argv0, execArgv, execPath} = require('process'); argv.forEach( item => { console.log(item); }) //打印當前工做進程的路徑 console.log(process.cwd()); //setImmediate(fn),不須要任什麼時候間參數,執行最慢 //process.nextTick(fn) //兩者的區別就是後者的執行會先於前者
process.nextTick()
會把任務放在當前事件循環隊列的隊尾,而setImmediate()
會把任務放在下一個隊列的隊首,而setTimeout()
會把任務放在它倆中間。和路徑有關的內置模塊
path.basename()
取得一個路徑的最後一部分文件名path.normalize()
幫助修正路徑path.join()
用於路徑拼接(參數爲多個路徑參數)path.resolve()
將一個相對路徑解析爲絕對路徑{basename, dirname, extname}
basename
完整名dirname
上級路徑名extname
後綴名{parse, format}
parse
用於解析當前路徑爲一個json格式的數據format
至關於格式化json數據爲一個字符串說明:__dirname
、__filename
老是返回文件的絕對路徑
process.cwd()
老是返回node命令所在文件夾
三個要點:
Buffer經常使用的方法
byteLength
統計buffer所佔字節數isBuffer
用來判斷目標數據是否是一個Bufferconcat
合併鏈接Bufferfrom
將目標數據轉換爲BuffertoString
用來轉換Buffer爲字符串eventEmitter.on('eventName',callback())
用於註冊監聽器eventEmitter.emit('eventName')
用於觸發事件const EventEmitter = require('events'); class CustomEvent extends EventEmitter { } const ce = new CustomEvent(); ce.on('eventName',callback); ce.emit('eventName','your msg to eventEmit',....); //有一個通用參數就叫error ce.on('error',fn); //Example ce.on('error',(err, item) => { console.log(err); console.log(item); }); ce.emit('error', new Error('出錯了'), Date().now);
針對事件只須要響應一次:
ce.once('test', ()=> { console.log(test); });
針對事件須要移除的話:
ce.removeListener('eventName',fn); //or ce.removeAllListeners('test');
首先須要注意的就是Node.js的設計模型就是錯誤優先的模式。
fs.readFile('fileUrl', 'utf8', (err, data) => { if(err) throw err; console.log(data); })
stat()
查看文件的詳細信息
const fs = require('fs'); fs.stat('fileUrl', (err, data) => { if (err) { throw err;//這裏能夠判斷文件是否存在 } console.log(data); });
rename()
更改文件名
fs.rename('./text.txt','hahah.ttx');
unlink
刪除文件fs.unlink('fileName', err => err);
readdir()
讀取文件夾mkdir()
建立文件夾rmdir()
刪除文件夾watch()
監視文件或目錄的變化fs.watch('fileUrl', { recursive:true //是否監視子文件夾 }, (eventType, fileName) => { console.log(eventType, fileName); })
readStream()
讀取流const rs = fs.createReadStream('urlPath'); rs.pipe(process.stdout);//導出文件到控制檯
writeStream()
寫入流pipe()
管道,導通流文件
const ws = fscreateWriteStream('urlPath'); ws.write('some content'); ws.end(); ws.on('finish',()=>{ console.log('done!!!'); });
.gitignore
/
表明項目根目錄\
表明是目錄!
表明取反*
表明任意一個字符?
匹配任意字符**
匹配任意目錄ESLint
完整配置.eslintrc.js
module.exports = { env: { es6: true, mocha: true, node: true }, extends: ['eslint:recommended', 'plugin:sort-class-members/recommended'], parser: 'babel-eslint', plugins: ['babel', 'sort-class-members'], root: true, rules: { 'accessor-pairs': 'error', // 強制 getter 和 setter 在對象中成對出現 'array-bracket-spacing': 'off', // 強制數組方括號中使用一致的空格 'arrow-parens': 'off', // 要求箭頭函數的參數使用圓括號 'arrow-spacing': 'error', // 強制箭頭函數的箭頭先後使用一致的空格 'babel/arrow-parens': ['error', 'as-needed'], 'babel/generator-star-spacing': ['error', 'before'], 'block-scoped-var': 'error', // 強制把變量的使用限制在其定義的做用域範圍內 'block-spacing': 'off', // 強制在單行代碼塊中使用一致的空格 'brace-style': 'off', // 強制在代碼塊中使用一致的大括號風格 camelcase: 'off', // 強制使用駱駝拼寫法命名約定 'comma-dangle': 'off', // 要求或禁止末尾逗號 'comma-spacing': 'off', // 強制在逗號先後使用一致的空格 'comma-style': 'off', // 強制使用一致的逗號風格 complexity: 'off', // 指定程序中容許的最大環路複雜度 'computed-property-spacing': 'error', // 強制在計算的屬性的方括號中使用一致的空格 'consistent-return': 'off', // 要求 return 語句要麼老是指定返回的值,要麼不指定 'consistent-this': 'error', // 當獲取當前執行環境的上下文時,強制使用一致的命名 'constructor-super': 'error', // 要求在構造函數中有 super() 的調用 curly: 'off', // 強制全部控制語句使用一致的括號風格 'default-case': 'error', // 要求 switch 語句中有 default 分支 'dot-location': ['error', 'property'], // 強制在點號以前和以後一致的換行 'dot-notation': 'off', // 強制在任何容許的時候使用點號 'eol-last': 'off', // 強制文件末尾至少保留一行空行 eqeqeq: ['error', 'smart'], // 要求使用 === 和 !== 'func-names': 'off', // 強制使用命名的 function 表達式 'func-style': ['error', 'declaration', { // 強制一致地使用函數聲明或函數表達式 allowArrowFunctions: true }], 'generator-star-spacing': 'off', // 強制 generator 函數中 * 號周圍使用一致的空格 'id-length': ['error', { // 強制標識符的最新和最大長度 exceptions: ['_', 'e', 'i', '$'] }], indent: ['error', 4, { // 強制使用一致的縮進 SwitchCase: 1 }], 'key-spacing': 'off', // 強制在對象字面量的屬性中鍵和值之間使用一致的間距 'keyword-spacing': ['off', { // 強制在關鍵字先後使用一致的空格 overrides: { case: { after: true }, return: { after: true }, throw: { after: true } } }], 'linebreak-style': 'off', 'lines-around-comment': 'off', 'max-depth': 'error', // 強制可嵌套的塊的最大深度 'max-nested-callbacks': 'off', 'max-params': ['error', 4], 'new-cap': 'off', 'new-parens': 'error', // 要求調用無參構造函數時有圓括號 'newline-after-var': 'off', 'no-alert': 'error', // 禁用 alert、confirm 和 prompt 'no-array-constructor': 'error', // 禁止使用 Array 構造函數 'no-bitwise': 'error', // 禁用按位運算符 'no-caller': 'error', // 禁用 arguments.caller 或 arguments.callee 'no-catch-shadow': 'off', 'no-class-assign': 'error', // 禁止修改類聲明的變量 'no-cond-assign': ['error', 'always'], // 禁止條件表達式中出現賦值操做符 'no-confusing-arrow': 'error', // 不容許箭頭功能,在那裏他們能夠混淆的比較 "no-console": 0, 'no-const-assign': 'error', // 禁止修改 const 聲明的變量 'no-constant-condition': 'error', // 禁止在條件中使用常量表達式 'no-div-regex': 'error', // 禁止除法操做符顯式的出如今正則表達式開始的位置 'no-dupe-class-members': 'error', // 禁止類成員中出現重複的名稱 'no-duplicate-imports': 'off', // disallow duplicate module imports 'no-else-return': 'error', // 禁止 if 語句中有 return 以後有 else 'no-empty-label': 'off', 'no-empty': 'off', 'no-eq-null': 'error', // 禁止在沒有類型檢查操做符的狀況下與 null 進行比較 'no-eval': 'error', // 禁用 eval() 'no-extend-native': 'error', // 禁止擴展原生類型 'no-extra-bind': 'error', // 禁止沒必要要的 .bind() 調用 'no-extra-parens': 'error', // 禁止沒必要要的括號 'no-floating-decimal': 'error', // 禁止數字字面量中使用前導和末尾小數點 'no-implied-eval': 'error', // 禁止使用相似 eval() 的方法 'no-inline-comments': 'error', // 禁止在代碼行後使用內聯註釋 'no-iterator': 'error', // 禁用 __iterator__ 屬性 'no-label-var': 'off', 'no-labels': 'off', 'no-lone-blocks': 'error', // 禁用沒必要要的嵌套塊 'no-lonely-if': 'off', 'no-loop-func': 'error', // 禁止在循環中出現 function 聲明和表達式 'no-mixed-requires': 'error', // 禁止混合常規 var 聲明和 require 調用 'no-mixed-spaces-and-tabs': 'off', 'no-multi-spaces': 'off', 'no-multi-str': 'off', 'no-native-reassign': 'error', // 禁止對原生對象賦值 'no-nested-ternary': 'error', // 不容許使用嵌套的三元表達式 'no-new-func': 'error', // 禁止對 Function 對象使用 new 操做符 'no-new-object': 'error', // 禁止使用 Object 的構造函數 'no-new-require': 'error', // 禁止調用 require 時使用 new 操做符 'no-new-wrappers': 'error', // 禁止對 String,Number 和 Boolean 使用 new 操做符 'no-new': 'error', // 禁止在非賦值或條件語句中使用 new 操做符 'no-octal-escape': 'error', // 禁止在字符串中使用八進制轉義序列 'no-path-concat': 'error', // 禁止對 __dirname 和 __filename進行字符串鏈接 'no-process-env': 'error', // 禁用 process.env 'no-process-exit': 'error', // 禁用 process.exit() 'no-proto': 'error', // 禁用 __proto__ 屬性 'no-restricted-modules': 'error', // 禁用指定的經過 require 加載的模塊 'no-return-assign': 'error', // 禁止在 return 語句中使用賦值語句 'no-script-url': 'error', // 禁止使用 javascript: url 'no-self-compare': 'error', // 禁止自身比較 'no-sequences': 'error', // 禁用逗號操做符 'no-shadow-restricted-names': 'error', // 禁止覆蓋受限制的標識符 'no-shadow': 'off', 'no-spaced-func': 'off', 'no-sync': 'off', // 禁用同步方法 'no-this-before-super': 'error', // 禁止在構造函數中,在調用 super() 以前使用 this 或 super 'no-throw-literal': 'error', // 禁止拋出非異常字面量 'no-trailing-spaces': 'error', // 禁用行尾空格 'no-undef-init': 'error', // 禁止將變量初始化爲 undefined 'no-undefined': 'off', 'no-underscore-dangle': 'off', 'no-unexpected-multiline': 'error', // 禁止出現使人困惑的多行表達式 'no-unneeded-ternary': 'error', // 禁止能夠在有更簡單的可替代的表達式時使用三元操做符 'no-unused-expressions': 'error', // 禁止出現未使用過的表達式 "no-unused-vars": [1, { // 禁止出現未使用過的變量 "vars": "all", "args": "after-used" }], 'no-use-before-define': 'error', // 不容許在變量定義以前使用它們 'no-useless-call': 'error', // 禁止沒必要要的 .call() 和 .apply() 'no-useless-concat': 'error', // 禁止沒必要要的字符串字面量或模板字面量的鏈接 'no-var': 'off', 'no-void': 'error', // 禁用 void 操做符 'no-warning-comments': 'off', 'no-with': 'off', 'object-curly-spacing': 'off', 'object-shorthand': 'error', // 要求或禁止對象字面量中方法和屬性使用簡寫語法 'one-var': 'off', 'operator-assignment': 'error', // 要求或禁止在可能的狀況下要求使用簡化的賦值操做符 'operator-linebreak': 'off', 'padded-blocks': 'off', 'prefer-arrow-callback': 'off', 'prefer-const': 'error', // 要求使用 const 聲明那些聲明後再也不被修改的變量 'prefer-spread': 'error', // 要求使用擴展運算符而非 .apply() 'prefer-template': 'off', // 要求使用模板字面量而非字符串鏈接 quotes: 'off', 'quote-props': 'off', radix: 'error', // 強制在parseInt()使用基數參數 'require-yield': 'error', // 要求generator 函數內有 yield "semi": ["error", "always"], // 要求或禁止使用分號 'semi-spacing': 'off', 'sort-vars': 'error', // 要求同一個聲明塊中的變量按順序排列 'space-before-blocks': 'off', 'space-before-function-paren': 'off', 'space-in-parens': 'off', 'space-infix-ops': 'off', 'space-unary-ops': 'off', 'spaced-comment': 'off', strict: 'off', 'valid-jsdoc': 'error', // 強制使用有效的 JSDoc 註釋 'vars-on-top': 'off', yoda: 'off', 'wrap-iife': 'off', 'wrap-regex': 'error' // 要求正則表達式被括號括起來 } }
http
模塊const http = require('http'); const chalk = require('chalk'); const hostname = '127.0.0.1'; const port = '3000'; const server = http.createServe((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello World'); }); server.listen(port, hostname, () => { const addr = `Server running at http://${hostname}:${port}/`; console.log(`${chalk.green(addr)}`); })
supervisor
監視文件模塊hotnode
熱啓動模塊完整代碼:請參照
console.assert(a===b,msg);
經常使用斷言庫:chai.js
//you should install mocha // $ npm install --save-dev mocha // you should know the '#math' only is it's description describe('#math', ()=> { describe('#add', ()=> { it('should return 5 when 2 + 3', () => { ecpect('your test','targetResult'); }); }); });
Note :若是你想只執行一個模塊的,你能夠在package.json中配置
"scripts": { "test": "mocha /url/xxx.js }
你能夠參照)
//常見測試方法 console.time('markPoint'); console.timeEnd('markPoint');
## 傳統測試天然就是人工點擊 ## 弊端就是發現錯誤不健全
==爬蟲==:按照必定的規則自動抓取網絡信息的程序
==反爬蟲==:
思路一:使用cheerio與http/https
//簡單示例 const cheerio = require('cheerio'); const https = require('https'); let html = ''; const $ = ''; https.get('url',res => { res.on('data',(data) => { html += data; }); res.on('finish',()=> { $ = cheerio.load(html); //some code }) })
思路二:puppeteer
index.js
const puppeteer = require('puppeteer'); const https = require('https'); const fs = require('fs'); (async () => { //跳過安裝 npm i --save puppeteer --ignore-scripts const browser = await puppeteer.launch({ executablePath: 'G:/chrome-win/chrome-win/chrome.exe' }); const page = await browser.newPage(); //指定瀏覽器去某個頁面 await page.goto('https://image.baidu.com'); // await page.cookies('https://image.baidu.com') // .then(data => { // console.info(data) // }); //調大視口,方便截圖,方便容納更多地圖 await page.setViewport({ width:2000, height:1000, }); //模擬用哪一個戶輸入 await page.keyboard.sendCharacter('車模'); //模擬用戶點擊搜索 await page.click('.s_search'); console.info('開始點擊查詢......'); //await page.screenshot({path: 'example.png'}); page.on('load', async()=> { console.info('頁面已加載完畢,開始爬取'); await page.screenshot({path: 'example.png'}); let srcs = await page.evaluate(() => { let img = document.querySelectorAll('img.main_img'); return Array.from(img).map(item => item.src); }); await srcs.forEach((item,index) => { if(/^https:/g.test(item)) https.get(item,res =>{ res.pipe(fs.createWriteStream(__dirname + `/img/${index}.png`)) .on('finish',()=>{ console.info(`已成功爬取${index + 1}條記錄!`); }); }) }) await browser.close(); }); })();
package.json
{ "name": "reptiles", "version": "1.0.0", "description": "This is a replite", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node index.js" }, "author": "vuejs@vip.qq.com", "license": "ISC", "dependencies": { "puppeteer": "^1.14.0" } }
## 初始化你的項目 $ npm init ## 創建文件 $ cd your project $ mkdir index.js ## 拷貝個人package.json ## 注意,這是重點,由於被牆,因此必須跳過安裝 $ npm i --save puppeteer --ignore-scripts ## 啓動項目 $ npm start
Note SomeDetails
puppeteer
,必須跳過Chromium
的鏈接Chromium
,在lanuch的時候必須用絕對路徑,切記不可把chrom.exe
單純拷貝到項目目錄page.waitFor(200)
,讓任務沉睡一下子這篇大長文就算完全結束了,我相信文章裏面還有不少不足或者小錯誤,誠懇的但願你們不要噴我。
"你能不能,在於你想不想!"
加油,每一天都是新生。
對於這篇文章,我也會不斷的完善它。