node课程宏任务队列举例队列:timer poll check
node事件循环:
清空微任务队列有两个时机
- 在第一次同步代码执行完毕后
- timer中所有宏任务执行完之后,会依次切换队列 timer —> poll —> check(比如:在切换为timer 切换为 poll 之前)
- 判断这2个的执行时机:前提条件,node中,setTimeout(() => {}, 0) = setTimeout(() => {}, 1) ```javascript
setTimeout(() => {}, 0) setImmediate(() => {}) // event loop 启动需要时间,如果直接运行这两行代码,会得到不确定顺序,是因为,启动如果花了1ms,会进入第二轮循环执行setTimeout,再setImmediate;如果没有1ms,那还是停留在第一轮循环,所以进入check阶段执行setiImmediate,再第二轮循环setTimeout
**浏览器事件循环:**<br />清空微任务队列有两个时机- 在第一个同步任务执行完毕后清空微任务队列- 在当前宏任务结束之后清空微任务队列- <br />相同点:在同步代码执行完毕后都会去看一眼微任务队列是否有微任务<br />不同点:(其实它们没有什么可比性啊!!!)- node事件循环中nextTick的优先级高于promise的优先级在基础讲解中学到的点- 会调试了- 写功能先写外层结构,先写需要方法名,再填充内容- 写一步测试一步- 学习源码的方法:先进入调试,再自己模拟实现,这样能加深印象,这也是快速了解一种新的API的方法,比拿着源码看有用多了- 学习源码就是要先会使用,再看源码- 边界条件应该放在独立功能的入口处<a name="zgm1h"></a>## linkList实现```javascript/*01 node + head + null02 head --->null03 size04 next element05 增加 删除 修改 查询 清空*/class Node {constructor(element, next) {this.element = elementthis.next = next}}class _getNode(index) {// second step: side conditionif (index < 0 || index >= this.size) {throw new Error('cross the side')}// first step: main logiclet currentNode = this.headfor (let i = 0; i < index; i++) {currentNode = currentNodex.next}}class LinkList {constructor(head, size) {this.head = nullthis.size = 0}add(index, element) {if (arguments.length === 1) {element = indexindex = this.size}if (index < 0 || index > this.size) {throw new Error('cross the border')}if (index === 0) {let head = this.headthis.head = new Node(element, head)} else {let preNode = this._getNode(index-1)preNode.next = new Node(element, preNode.next)}this.size++}remove(index) {if (index === 0) {// why can not head.next = head.next.next?let head = this.headthis.head = head.next} else {let preNode = this._getNode(index-1)preNode.next = preNode.next.next}}set(index, element) {let node = this._getNode(index)node.element = element}get(index) {return this._getNode(index)}clear() {this.head = nullthis.size = 0}}// testconst l1 = new LinkedList()l1.add('node1')console.log(l1)// resultLinkedList { head: Node { element: 'node1', next: null }, size: 1 }
require实现
const { dir } = require('console')const fs = require('fs')const path = require('path')const vm = require('vm')function Module (id) {this.id = idthis.exports = {}console.log(1111)}Module._resolveFilename = function (filename) {// 利用 Path 将 filename 转为绝对路径let absPath = path.resolve(__dirname, filename)// 判断当前路径对应的内容是否存在()if (fs.existsSync(absPath)) {// 如果条件成立则说明 absPath 对应的内容是存在的return absPath} else {// 文件定位let suffix = Object.keys(Module._extensions)for(var i=0; i<suffix.length; i++) {let newPath = absPath + suffix[i]if (fs.existsSync(newPath)) {return newPath}}}throw new Error(`${filename} is not exists`)}Module._extensions = {'.js'(module) {// 读取let content = fs.readFileSync(module.id, 'utf-8')// 包装content = Module.wrapper[0] + content + Module.wrapper[1]// VMlet compileFn = vm.runInThisContext(content)// 准备参数的值let exports = module.exportslet dirname = path.dirname(module.id)let filename = module.id// 调用compileFn.call(exports, exports, myRequire, module, filename, dirname)},'.json'(module) {let content = JSON.parse(fs.readFileSync(module.id, 'utf-8'))module.exports = content}}Module.wrapper = ["(function (exports, require, module, __filename, __dirname) {","})"]Module._cache = {}Module.prototype.load = function () {let extname = path.extname(this.id)Module._extensions[extname](this)}function myRequire (filename) {// 1 绝对路径let mPath = Module._resolveFilename(filename)// 2 缓存优先let cacheModule = Module._cache[mPath]if (cacheModule) return cacheModule.exports// 3 创建空对象加载目标模块let module = new Module(mPath)// 4 缓存已加载过的模块Module._cache[mPath] = module// 5 执行加载(编译执行)module.load()// 6 返回数据return module.exports}let obj = myRequire('./v')let obj2 = myRequire('./v')console.log(obj.age)
js中任务执行和node中任务执行对比
// js中任务执行setTimeout(() => {console.log('s1')Promise.resolve().then(() => {console.log('p2')})Promise.resolve().then(() => {console.log('p3')})})Promise.resolve().then(() => {console.log('p1')setTimeout(() => {console.log('s2')})setTimeout(() => {console.log('s3')})})// p1 s1 p2 p3 s2 s3// node中任务执行setTimeout(() => {console.log('s1')Promise.resolve().then(() => {console.log('p1')})process.nextTick(() => {console.log('t1')})})Promise.resolve().then(() => {console.log('p2')})console.log('start')setTimeout(() => {console.log('s2')Promise.resolve().then(() => {console.log('p3')})process.nextTick(() => {console.log('t2')})})console.log('end')// start, end, p2, s1, s2 , t1, t2, p1, p3
控制写入速度
/*** 需求:“拉勾教育” 写入指定的文件* 01 一次性写入* 02 分批写入* 03 中文一次就是3位,我还疑惑为啥打印了4次* 对比:*/let fs = require('fs')let ws = fs.createWriteStream('test.txt', {highWaterMark: 3})// ws.write('拉勾教育')let source = "拉勾教育".split('')let num = 0let flag = truefunction executeWrite () {flag = truewhile(num !== 4 && flag) {flag = ws.write(source[num])num++}}executeWrite()ws.on('drain', () => {console.log('drain 执行了')executeWrite()})// pipe// resultdrain 执行了drain 执行了drain 执行了drain 执行了
redis的由来
- 因为mysql数据库的开发者不满足于性能,所以redidis一定是一款高性能的
- remote dictionary server 远程字典服务器
