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

  1. **浏览器事件循环:**<br />清空微任务队列有两个时机
  2. - 在第一个同步任务执行完毕后清空微任务队列
  3. - 在当前宏任务结束之后清空微任务队列
  4. - <br />
  5. 相同点:在同步代码执行完毕后都会去看一眼微任务队列是否有微任务<br />不同点:(其实它们没有什么可比性啊!!!)
  6. - node事件循环中nextTick的优先级高于promise的优先级
  7. 在基础讲解中学到的点
  8. - 会调试了
  9. - 写功能先写外层结构,先写需要方法名,再填充内容
  10. - 写一步测试一步
  11. - 学习源码的方法:先进入调试,再自己模拟实现,这样能加深印象,这也是快速了解一种新的API的方法,比拿着源码看有用多了
  12. - 学习源码就是要先会使用,再看源码
  13. - 边界条件应该放在独立功能的入口处
  14. <a name="zgm1h"></a>
  15. ## linkList实现
  16. ```javascript
  17. /*
  18. 01 node + head + null
  19. 02 head --->null
  20. 03 size
  21. 04 next element
  22. 05 增加 删除 修改 查询 清空
  23. */
  24. class Node {
  25. constructor(element, next) {
  26. this.element = element
  27. this.next = next
  28. }
  29. }
  30. class _getNode(index) {
  31. // second step: side condition
  32. if (index < 0 || index >= this.size) {
  33. throw new Error('cross the side')
  34. }
  35. // first step: main logic
  36. let currentNode = this.head
  37. for (let i = 0; i < index; i++) {
  38. currentNode = currentNodex.next
  39. }
  40. }
  41. class LinkList {
  42. constructor(head, size) {
  43. this.head = null
  44. this.size = 0
  45. }
  46. add(index, element) {
  47. if (arguments.length === 1) {
  48. element = index
  49. index = this.size
  50. }
  51. if (index < 0 || index > this.size) {
  52. throw new Error('cross the border')
  53. }
  54. if (index === 0) {
  55. let head = this.head
  56. this.head = new Node(element, head)
  57. } else {
  58. let preNode = this._getNode(index-1)
  59. preNode.next = new Node(element, preNode.next)
  60. }
  61. this.size++
  62. }
  63. remove(index) {
  64. if (index === 0) {
  65. // why can not head.next = head.next.next?
  66. let head = this.head
  67. this.head = head.next
  68. } else {
  69. let preNode = this._getNode(index-1)
  70. preNode.next = preNode.next.next
  71. }
  72. }
  73. set(index, element) {
  74. let node = this._getNode(index)
  75. node.element = element
  76. }
  77. get(index) {
  78. return this._getNode(index)
  79. }
  80. clear() {
  81. this.head = null
  82. this.size = 0
  83. }
  84. }
  85. // test
  86. const l1 = new LinkedList()
  87. l1.add('node1')
  88. console.log(l1)
  89. // result
  90. LinkedList { head: Node { element: 'node1', next: null }, size: 1 }

require实现

  1. const { dir } = require('console')
  2. const fs = require('fs')
  3. const path = require('path')
  4. const vm = require('vm')
  5. function Module (id) {
  6. this.id = id
  7. this.exports = {}
  8. console.log(1111)
  9. }
  10. Module._resolveFilename = function (filename) {
  11. // 利用 Path 将 filename 转为绝对路径
  12. let absPath = path.resolve(__dirname, filename)
  13. // 判断当前路径对应的内容是否存在()
  14. if (fs.existsSync(absPath)) {
  15. // 如果条件成立则说明 absPath 对应的内容是存在的
  16. return absPath
  17. } else {
  18. // 文件定位
  19. let suffix = Object.keys(Module._extensions)
  20. for(var i=0; i<suffix.length; i++) {
  21. let newPath = absPath + suffix[i]
  22. if (fs.existsSync(newPath)) {
  23. return newPath
  24. }
  25. }
  26. }
  27. throw new Error(`${filename} is not exists`)
  28. }
  29. Module._extensions = {
  30. '.js'(module) {
  31. // 读取
  32. let content = fs.readFileSync(module.id, 'utf-8')
  33. // 包装
  34. content = Module.wrapper[0] + content + Module.wrapper[1]
  35. // VM
  36. let compileFn = vm.runInThisContext(content)
  37. // 准备参数的值
  38. let exports = module.exports
  39. let dirname = path.dirname(module.id)
  40. let filename = module.id
  41. // 调用
  42. compileFn.call(exports, exports, myRequire, module, filename, dirname)
  43. },
  44. '.json'(module) {
  45. let content = JSON.parse(fs.readFileSync(module.id, 'utf-8'))
  46. module.exports = content
  47. }
  48. }
  49. Module.wrapper = [
  50. "(function (exports, require, module, __filename, __dirname) {",
  51. "})"
  52. ]
  53. Module._cache = {}
  54. Module.prototype.load = function () {
  55. let extname = path.extname(this.id)
  56. Module._extensions[extname](this)
  57. }
  58. function myRequire (filename) {
  59. // 1 绝对路径
  60. let mPath = Module._resolveFilename(filename)
  61. // 2 缓存优先
  62. let cacheModule = Module._cache[mPath]
  63. if (cacheModule) return cacheModule.exports
  64. // 3 创建空对象加载目标模块
  65. let module = new Module(mPath)
  66. // 4 缓存已加载过的模块
  67. Module._cache[mPath] = module
  68. // 5 执行加载(编译执行)
  69. module.load()
  70. // 6 返回数据
  71. return module.exports
  72. }
  73. let obj = myRequire('./v')
  74. let obj2 = myRequire('./v')
  75. console.log(obj.age)

js中任务执行和node中任务执行对比

  1. // js中任务执行
  2. setTimeout(() => {
  3. console.log('s1')
  4. Promise.resolve().then(() => {
  5. console.log('p2')
  6. })
  7. Promise.resolve().then(() => {
  8. console.log('p3')
  9. })
  10. })
  11. Promise.resolve().then(() => {
  12. console.log('p1')
  13. setTimeout(() => {
  14. console.log('s2')
  15. })
  16. setTimeout(() => {
  17. console.log('s3')
  18. })
  19. })
  20. // p1 s1 p2 p3 s2 s3
  21. // node中任务执行
  22. setTimeout(() => {
  23. console.log('s1')
  24. Promise.resolve().then(() => {
  25. console.log('p1')
  26. })
  27. process.nextTick(() => {
  28. console.log('t1')
  29. })
  30. })
  31. Promise.resolve().then(() => {
  32. console.log('p2')
  33. })
  34. console.log('start')
  35. setTimeout(() => {
  36. console.log('s2')
  37. Promise.resolve().then(() => {
  38. console.log('p3')
  39. })
  40. process.nextTick(() => {
  41. console.log('t2')
  42. })
  43. })
  44. console.log('end')
  45. // start, end, p2, s1, s2 , t1, t2, p1, p3

控制写入速度

  1. /**
  2. * 需求:“拉勾教育” 写入指定的文件
  3. * 01 一次性写入
  4. * 02 分批写入
  5. * 03 中文一次就是3位,我还疑惑为啥打印了4次
  6. * 对比:
  7. */
  8. let fs = require('fs')
  9. let ws = fs.createWriteStream('test.txt', {
  10. highWaterMark: 3
  11. })
  12. // ws.write('拉勾教育')
  13. let source = "拉勾教育".split('')
  14. let num = 0
  15. let flag = true
  16. function executeWrite () {
  17. flag = true
  18. while(num !== 4 && flag) {
  19. flag = ws.write(source[num])
  20. num++
  21. }
  22. }
  23. executeWrite()
  24. ws.on('drain', () => {
  25. console.log('drain 执行了')
  26. executeWrite()
  27. })
  28. // pipe
  29. // result
  30. drain 执行了
  31. drain 执行了
  32. drain 执行了
  33. drain 执行了

redis的由来

  • 因为mysql数据库的开发者不满足于性能,所以redidis一定是一款高性能的
  • remote dictionary server 远程字典服务器