foundation


EventLoop

JS是一种单线程语言,它和多线程语言最大的不同就是只有一个线程,如果线程中有任务阻塞那么线程将出现排队情况。设计单线程的原因是因为JS在设计之初是用来作为浏览器的脚本语言的,为了防止处理dom多个线程处理出现资源抢占的情况,所以设计为单线程。单线程中又把任务分为同步任务和异步任务,而异步任务中将计时器,io操作等规划为宏任务,promise等规划为微任务。当出现任务时浏览器会将任务放到调用栈中等待主线程执行。在调用栈中同步任务会按照顺序执行,而异步任务则按照任务队列的形式进行执行。这个任务队列就行eventloop。一般来讲是执行完宏任务后寻找未执行的微任务,微任务执行完成后执行下一个宏任务,循环往复直至任务队列清空。

  console.log('a');

  setTimeout(function() {
      console.log('b');
      process.nextTick(function() {
          console.log('c');
      })
      new Promise(function(resolve) {
          console.log('d');
          resolve();
      }).then(function() {
          console.log('e')
      })
  })
  process.nextTick(function() {
      console.log('f');
  })
  new Promise(function(resolve) {
      console.log('g');
      resolve();
  }).then(function() {
      console.log('h')
  })

  setTimeout(function() {
      console.log('i');
      process.nextTick(function() {
          console.log('j');
      })
      new Promise(function(resolve) {
          console.log('k');
          resolve();
      }).then(function() {
          console.log('l')
      })
  })

//   A
// g
// f
// h
// b
// d
// c
// e
// i
// k
// j
// l

GC

JS和JAVA等语言依赖于GC回收机制,而C,C++等语言则是可以手动释放内存空间。
垃圾回收的基本思路是查找内存中的所有对象,然后查看哪些不需要,然后释放对象占用的内存。
在V8中,js的内存空间可以分为堆和栈,栈主要用处存在原始类型(即不存在引用类型的数据类型),堆会根据先进后出的原则进行垃圾清除。
堆中存放引用对象,我们主要讨论的就是GC的栈回收机制
G8回收的基本思想是依照日常使用的情况提出一种假设,即在js运行环境中的大部分对象存在时间很短,基于这个思想设计了新生代内存和老生代内存。

新生代

新生代内存将内存空间均分为两份from和to,对象被初次分配时会进入from空间,在from空间不足或者超出阈值时,会进行Minor GC(即复制整理算法),检查存活对象然后整理连续移动到to同时释放from,循环往复。每经历一次Minor GC存活的对象age+1,一般超过两次后会晋升到老生代。

老生代

老生代主要用处存放生命周期长或者经历多次minor GC存活的对象。老生代主要使用标记-清除 和 标记-整理两种算法。
标记清除,在标记阶段遍历所有对象并标记活动对象,在清除阶段清除非活动对象(即无引用
标记整理,在清除阶段之上,考虑内存连续性,进行排序整理,解决碎片化问题。
Picsee-20230725170823.png

V8

promise

promise 并发限制

const promisePool = async function(functions, n) {
  await Promise.all([...new Array(n)].map(async () => {
    while(functions.length){
      await functions.shift()();
    }
  }))
}

/**
 * @param {Function[]} functions
 * @param {number} n
 * @return {Function}
 */
var promisePool = async function (functions, n) {
   let queue = new set();
   let results = [];
   for (const task of functions){
    //执行当前任务
      const x = task().then((res) => {
        result.push(res);
        queue.delete(task);
      })
      queue.add(task);
      // 当queue的大小超过阈值后使用await阻塞for循环, 等待前面加入queue中的task的执行结果,以此确保queue的数量不超过阈值
      if(queue.size > n){
        await Promise.race(queue)
      }
      // 确保所有任务执行完成后再返回, allSettled 无论成功失败都等待所有任务执行完毕后返回
      await Promise.allSettled(queue);
      return resolts;
   }
};

/**
 * const sleep = (t) => new Promise(res => setTimeout(res, t));
 * promisePool([() => sleep(500), () => sleep(400)], 1)
 *   .then(console.log) // After 900ms
 */

手写promise

const State = Map({
  pending: 'PENDING',
  success: 'SUCCESS',
  rejected: 'REJECTED',
})
class Promise {
  constructor(excutor) {
    this.status = State.pending;
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    let resolve = (value) => {
      if (this.status === State.pending) {
        this.status = State.success;
        this.value = value;
        this.onResolvedCallbacks.forEach(fn => fn());
      }
    };
    let reject = (reason) => {
      if (this.status === State.pending) {
        this.status = State.rejected;
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };
    try {
      excutor(resolve, reject)
    } catch (err) {
      reject(err);
    }

    then(onFullfilled, onRejected) {
      if (this.status === State.success) {
        onFullfilled(this.value)
      }
      if (this.status === State.rejected) {
        onRejected(this.reason)
      }

      if (this.status === State.pending) {
        this.onResolvedCallbacks.push(() => {
          onFullfilled(this.value)
        })
        this.onRejectedCallbacks.push(() => {
          onRejected(this.reason)
        })
      }
    }
  }
}

参考全部实现

http 1, 2, 3

http1.1
存在的问题

  • 高延迟,队头阻塞
  • 无状态
  • 明文传输
  • 不支持服务端推送
    http2

http2 基于 http和ssl架构增加了spdy协议,主要是用来解决http1.1存在的请求头巨大,队头阻塞问题,由于只是增加在应用和ssl层之间的层,因此可以很好的向下兼容。
其优点是基于tcp压缩了请求头,增加了服务端推送和多路复用和可选的加密通讯。但是人就存在tcp链接的延时和多路复用带来的服务器压力以及timeout问题。队头阻塞也有可能出现因为在多路复用中可能会存在请求失败然后多次renpost的情况
http3
h3是基于udp实现的quic协议,虽然是udp但是quic确保了可靠传输,确保数据可达。而且udp是不需要进行握手的,因此比tcp更快,并且quic还引入了类似http2的流和多路复用。
http 1 2 3
http 面试

httpcode

301,303,305

websocket

get 和 post 的区别

TCP/Ip, UDP

storage

webpack

webpack 是什么

webpack 的核心原理是什么

热更新原理

Picsee-20230727143846.png
Picsee-20230727144045.png

npm run dev启动阶段,webpack会插入两个runtime文件,然后监听代码改动通过内部的sendstats方法发送hash和ok,hash是用来作为下次更新的标记。然后创建http服务即我们常见的localhost80以及socket服务,建立连接后向本地服务发送hash和ok。此时用户访问,我们将webpack打包好的bundle和html进行展示。在修改代码阶段,重新编译生成hot-uopdate.js 和json布丁,执行webpackhotupdate(根据hash位置进行局部更新引入,然后发送hash和ok)
webpack-hotreload

babel是什么

babel的工作原理

mock工程化

  • 硬编码
  • js拦截
  • 网络代理拦截
  • mock-server
    我们采用的是mock-server的形式,通过env配置不同的模式对数据进行mock处理,搭配yapi进行,具体的规则是在对应未完成的开发的借口增加mock-xx进行匹配其余则走正常的真实api

sentry原理

性能

性能

错误

错误

每秒打印一次,直到count归0,忘记边界情况
ref,父子组件通讯,我直接给扯到redux/mobx,flux上了,有点过于底层。深入也不能太偏离主意愿
ts语法忘记了,但是概念都记得需要补一下。


  TOC