huenchao / questions

每天想到的问题,都放在issue中。
6 stars 2 forks source link

esm vs cjs #1

Open huenchao opened 4 years ago

huenchao commented 4 years ago

关注的问题

  1. 各自的实现机制?
  2. 在nodejs中怎么抹平他们?
  3. 为什么要出现esm这种文件加载方式?
huenchao commented 4 years ago

V8前置知识:

  1. Isolates: 是v8的实例,我们的js垃圾回收(gc),执行上下文都依赖它。每个Isolate都是分配在heap里的。

  2. Contexts: 我们有了Isolate,就有了一片内存作为执行环境,我们还需要一个global scope。它包含了很多全局变量和全局函数(eg:console, exports, module, process, require())。我们叫它V8::Context。然后我们的jscode 就放在这个sandbox里执行。 image

  3. Handles:它是对js对象(v8::value)的封装,为什么需要对v8::value进行封装? 我们在Isolate这个heap里存储了js对象,Isolate的一个作用就是gc,假设一个场景:你在addon里生成了一个Local的v8::value,然后这个addon函数执行完毕了,这个v8::value就应该被销毁了,那怎么通知v8去回收这片内存呢? v8通过对这些变量包装一层v8::handle,因为Local handle它是存在stack里的,然后对这个handle类的析构函数里加个notify的方法,通知v8去销毁数据内存,最终实现gc。

  4. HandleScope:我们知道Handle被销毁的时候,会通知v8清理内存,那存在v8里的数据和Handle之间是怎么关联起来的呢?其实Handle的构造函数返回一个V8 bookkeeping。它的数据结构的作用是将Handle映射到v8的内存,可以看这幅图:

    WeChatd2d5467439d017281b2b643b15f1425f

    但是!!这些Local handles是不会在他们的析构函数和构造函数里,直接操作bookkeeping的,这些Local handles全部关联到一个叫做HandleScope的对象里,统一管理。比如说,你在一个函数里定义了好几个变量,这好几个变量关联的handles,全部都被加到这个HandleScope里,当你这个函数执行完毕后(假设这些变量没有被别的地方引用了),通过HandleScope统一处理v8 heap里的内存(执行gc)。这个HandleScope就被删除掉了,然后它前面一个HandleScope就被激活了,这就是作用域链的真相了。

huenchao commented 4 years ago

common js 和 es module 的loader 差异

  1. commonjs是sync load(dist加载文件) + inline execution(wasm api 对代码执行,再对内存数据复制)
  2. esm 是 async load + sync execution(live binding)