欲练此功,必先自宫;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)
,让任务沉睡一下子这篇大长文就算完全结束了,我相信文章里面还有不少不足或者小错误,诚恳的但愿你们不要喷我。
"你能不能,在于你想不想!"
加油,每一天都是新生。
对于这篇文章,我也会不断的完善它。