把v8当做新的框架,新的语言来学习,从上JS,从下C++;在V8里有着自己一套的API和规则。 version:6.*
基本概念
内存机制
javascript中使用的数据类型,声明的变量,由chrome v8管理内存机制管理;
node重要的两部分:
- chrome V8 提供 js运行环境,解释执行js
- libuv 提供跨平台的事件循环机制,以及各种基础库
c++扩展 在Chrome V8中的实例中创建的变量,能够被js访问到,js创建,声明的数据,也能在一定的条件下被C++扩展访问;
Chrome V8 中创建的数据存储单元,不能被显示的回收,只能等待内存回收机制判断;
新生代
分配的对象小,垃圾回收频繁;
新生代内存采用Scavenge算法进行垃圾回收;
当分配新的数据,指向内存区指针到了新生代内存末尾,触发一次清理(没地方可用了);
当经历到第二次清理时,会晋升至老生代(查过一次还不死的数据);
当垃圾回收时To空间已经被占据25%,会晋升至老生代
老生代
老生代数据量大,采用Scavenge,耗时大,其使用Mark-sweep(标记清除)+Mark-Compact(标记整理)
- Mark-sweep 标记清理,标记阶段,标记活着的数据;清理阶段,清理未被标记的数据。
- Mark-Compact 标记整理,当老生代空间不足以存放晋升过来的新生代数据时,使用此方法;因为标记清理会造成内存碎片(内存空间不连续),解决办法就是在标记清理的清除阶段,让活着的对象整齐排放,留出空间;
隔离实例(Isolate)
v8引擎实例!!单个实例内部有着独立的堆管理,垃圾回收;如果自定义node。为其添加多个隔离实例,那么实例之间互不干扰。
上下文(Context)
上下文对象,定义JS执行环境的对象
脚本(Script)
包含已经编译好的JS脚本对象
常用数据类型
js层面的数据到了v8层面,这些数据都基于V8:value 这个基类而来,当不确定数据的类型是,使用v8:value可以解决不方便之处。
Value主要有两种方法Is判断数据类型,To转化数据类型(实际是得到另一种类型的的句柄)
句柄
什么时候,对象数据才是不被引用的对象,即死亡对象数据?
当一个对象不再被句柄引用之后,他就是垃圾;句柄不同于指针,垃圾回收的时候,内存数据会被移动,如果使用指针,最后指向的数据就会不对,使用句柄,数据的引用关系保存在垃圾回收器;
句柄作用域
句柄活动的范围,一般在函数体开始声明。一个句柄作用域管理其域中的句柄,感觉句柄作用域是湖泊,句柄是鱼!
本地句柄
句柄是v8中定义的一种数据对象,有着自己定义,声明,属性方法,
静态成员函数(6.17.1)
成员函数
- NEW(创建)
- Clear(清除)
- IsEmpty(判断空句柄)
- AS/Cast(不同数据类型的本地句柄转换)
持久句柄
其提供堆内存中一个JS对象的引用
当JS对象引用只有一个(弱)持久句柄时,v8垃圾回收会触发一个回调;
永生句柄(Eternal)
永生了
待实本地句柄(Maybe Local)
特别的本地句柄,当不确定获取的本地句柄是否为空,用此句柄类型提醒自己
句柄作用域
可以把句柄作用域看做小说里面的一方世界,句柄是这方世界的生灵。作用域结束的时候,这方“世界”的生灵基本都会被抹去,除去个别几种。
一般句柄作用域
可逃句柄作用域
模板(Template)
函数模板(Function Template)
按照官网的介绍,函数模板用于运行时创建函数,且在一个上下文通过函数模板有且创建一个函数,被创建的函数生命周期与上下文的生命周期一致。
通过下面的代码,我们可以通过函数模板到将C++等扩展函数,为JS所用;
void Method(const <Value> &args){
Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(String::NewFromUtf8(isolate,"this is a function"));
}
void init(Local<Object> exports)
{
Isolate* isolate =Isolate::GetCurrent();
HandleScope scope(isolate);
Local<FunctionTemplate> funtem = FunctionTemplate::New(isolate,Method);
Local<Function> fn = funtem -> GetFunction();
Local<String> name = String::NewFromUtf8(isolate,"functionName");
fn->SetName(name);
exports->Set(name,fn);
}
对象模板(Object Template)
官方介绍很少,运行时创建对象;添加到Object Template 的属性,其创建的对象也会拥有这个属性(类似原型链);
访问器(accessor)
在访问(get)或操作(set)对象特定属性时可以做某些事情;
对象模板通过SetAccessor()设置访问器;
拦截器(Interceptor)
对于一个对象实例所有操作进行拦截操作;
同样是对象模板上的操作,通过SetHandler()来实现;
从api上来看有两种实现方式:
- SetHandler (const NamedPropertyHandlerConfiguration &configuration)
- SetHandler (const IndexedPropertyHandlerConfiguration &configuration)
前者通过属性名字限制,后者通过属性下标
内置对象
内置字段,js层面不可见,只能在c++层面可见且操作;
内置对象除了是v8中定义的对象数据之外
还可以操作C++ 中自定义的struct/数据类型.这些数据类型和结构是v8没有的。
常用数据类型
V8文档
v8::Value 可以说是其他数据类型的基类了。
在关于v8::Value的文档中,我们可以看出关于Value的API大致有以下几种:
IS
TO
string
创建一个v8:String
// 将char* 转化成string
MaybeLocal<String> mbtestString = String::NewFromUtf8(isolate,"if like is time",NewStringType::kNormal);
Local<String> testString = mbtestString.ToLocalChecked();
将v8:String转成char
String::Utf8Value charStr(testString);
if(charStr.length() !=0){ // 上述转换可能会失败,length=0
char* ret = *charStr;
printf("%s\n",ret);
}
数值类型
Number、Interger、Int32、Uint32
使用起来基本都是New()或者Value()
Boolean
Object
不考虑Obj 作为function或者其他拦截器,访问器等功能的化,仅仅类似JS Object 去考虑功能,初始化,set,get,del 等对象操作
Local<Object> obj = Object::New(isolate); // 用obj 设置值,获取值,删除值
Local<String> key = String::NewFromUtf8(isolate,"objkey",NewStringType::kNormal).ToLocalChecked();
Local<Number> value = Number::New(isolate,1234);
obj->Set(context,key,value).FromJust();// 校验结果通过 FromJust来触发异常使程序崩溃
Local<Value> getValue = obj->Get(context,key).ToLocalChecked();
Local<Number> getValueNum = getValue->ToNumber(context).ToLocalChecked();
printf("obj get value is %f\n",getValueNum->Value());
obj->Delete(context,key).FromJust();
Local<Value> getValueDel = obj->Get(context,key).ToLocalChecked(); // 这里取值已经取不到值了
Local<Number> getValueNumDel = getValueDel->ToNumber(context).ToLocalChecked();
printf("obj get value is %f\n",getValueNumDel->Value());
Array
New 一个
Local<Array> arr = Array::New(isolate,10);//长度为10的数组
set&&get
数组继承Object.所以有着Object的方法;
// Get
MaybeLocal< Value > Get (Local< Context > context, uint32_t index)
// Set
Maybe< bool > Set (Local< Context > context, uint32_t index, Local< Value > value)
简单使用
尝试存取arr中的一个string
Local<Array> arr = Array::New(isolate,10);
char ret[512];
strcpy(ret,"下标为0的值");
printf("数组设置的值是:%s\n", ret);
//存
arr->Set(context,0,String::NewFromUtf8(isolate,ret,NewStringType::kNormal).ToLocalChecked());
// 取
Local<Value> arrvalue = arr->Get(context,0).ToLocalChecked();
if(arrvalue->IsString()){
printf("判断一下是不是string");
}
String::Utf8Value arrvaluechar(arrvalue);
if(arrvaluechar.length() !=0){
char* retarr = *arrvaluechar;
printf("Arr index 0 get value: %s\n", retarr);
}
Function
函数来源,从外部而来的value类型是函数,那么可以通过Cast将其转化成Function;还有就是C++层面通过函数模板创建的Function;
利用Call调用外部的方法;
下面用1+1等方式接入chrome V8 层面对函数类型的操作
void Add(const FunctionCallbackInfo<Value>& args)
{
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Local<Number> num1 = args[0].As<Number>();
Local<Number> num2 = args[1].As<Number>();
Local<Function> func =args[2].As<Function>();// 回调函数
Local<Value> null = v8::Null(isolate); // 回调函数this
double addret = num1->Value() + num2->Value();
Local<Number> value = Number::New(isolate, addret);
Local<Value> reArgv[1] = {value};
func->Call(context, null, 1, reArgv);
args.GetReturnValue().Set(value);
}
编译之后使用
const test =require("../build/Release/addon.node");
test(1,1,(ret)=>{
console.log(ret); //2
})
其中FunctionCallbackInfo为方法的参数,参数通过数组下标获取;ReturnValue是函数返回值的载体,可以设置返回值;
JSON(parse)
异常
TryCatch
trycatch 也是一种数据类型,用来对v8层面的异常捕获;
其他
Maybe
v8有许多返回maybe 类型的api;比如V8:Object的Set方法;Maybe的类型具有不确定性,犹如他的名字一样,它可能返回bool也可能返回无值。
在Object的例子中,我试图设置一个key的值,其返回一个Maybe ,不确定是否成功使用FromJust()来处理;
Maybe 有以下判断数据的成员函数:
IsNothing()
是否具有值 |
---|
IsJust()
FromJust()
FromMaybe()
| 返回本体值,没有则返回默认值 |
资源
总结
能看出,对数据的操作,都是在c++基础之上,借助v8的规则,运转规则;但是相对而言操作比较繁琐;