在js中,当使用promise,会将当前任务加入事件执行的微任务队列,有且只有这一种方法可以,因为当使用了promise,在JS引擎中会触发VM::queueMicrotask,会向m_microtaskQueue队列中压入事件,在V8中只有这一种暴露方式,没有其他接口可以调用这个方法。
void VM::queueMicrotask(JSGlobalObject& globalObject, Ref<Microtask>&& task)
{
m_microtaskQueue.append(makeUnique<QueuedTask>(*this, &globalObject, WTFMove(task)));
}
然后会执行VM::drainMicrotask,只要m_microtaskQueue不为空就会一直取微任务队列第一个去执行。
void VM::drainMicrotasks()
{
do {
while (!m_microtaskQueue.isEmpty()) {
m_microtaskQueue.takeFirst()->run();
if (m_onEachMicrotaskTick)
m_onEachMicrotaskTick(*this);
}
didExhaustMicrotaskQueue();
} while (!m_microtaskQueue.isEmpty());
finalizeSynchronousJSExecution();
}
所以Promise会将事件放到微任务队列的最后一位,然后继续执行,如果promise嵌套,内层的promise也会被放到微任务队列的最末尾,然后执行的时候再将其中的任务放到队列的末尾。
但是相比于微任务是js-core中自带的基础设施,js-core源代码中是不包含宏任务相关内容的,对于宏任务的相关内容是在C++的js引擎中实现的,单个js代码是通过语句是通过evaluateScript进行执行,而宏任务的实现相当于在C++中通过循环来去执行多个evaluateScript方法,而每个evaluateScript在执行前都有lock保证队列已经清空
下面是宏任务实现的伪代码:
// 初始化JS的执行环境
JSContext* context = [[JSContext alloc] init];
// 初始化C++环境的宏任务队列
NSMutableArray * macroTaskQueue = [[NSMutableArray alloc] init];
// 创建微任务锁
NSConditionLock* condLock = [[NSConditionLock alloc] initWithCondition:0];
// 引入js中的console.log方法,并转换为NSlog输出
context[@"console"] = [JSValue valueWithNewObjectInContext:context];
context[@"console"][@"log"] = ^(JSValue* s) {
NSLog(@"%@", [s toString]);
};
// 引入setTimeout方法
context[@"setTimeout"] = ^(JSValue* f, JSValue* duration) {
NSThread* timer = [[NSThread alloc]initWithBlock:^{
[NSThread sleepForTimeInterval:[duration toDouble] / 1000]; // 休眠1秒
[condLock lock]; // 使用锁
[macroTaskQueue addObject:f]; // 将任务的压入引擎宏任务队列
[condLock unlockWithCondition:1]; 将微任务锁设置为1
//[f callWithArguments:@[]];
}];
[timer start];
};
NSThread* scanner = [[NSThread alloc]initWithBlock:^{
char sourceCode[1024];
while(scanf("%[^\n]", sourceCode) != -1) {
getchar();
[condLock lock];
[macroTaskQueue addObject:[NSString stringWithUTF8String: sourceCode]];
[condLock unlockWithCondition:1];
}
}];
[scanner start];
while(true) { //Event Loop
[condLock lockWhenCondition:1]; // 将锁设置位1
for (id task in macroTaskQueue){
if([task isKindOfClass:JSValue.class])
[task callWithArguments:@[]];
if([task isKindOfClass:NSString.class]) {
JSValue* result = [context evaluateScript:task]; // 执行js内容
NSLog(@"%@", [result toString]);
}
}
[macroTaskQueue removeAllObjects]; // 将宏任务队列清空
[condLock unlockWithCondition:0]; // 将锁设置位0
}
我们都知道addEventListener() 的参数约定是:useCapture是可选参数,默认值为false,目前DOM 规范做了修订:addEventListener() 的第三个参数可以是个对象值了。passive就是告诉浏览器我可不可以用stopPropagation...
在WebApp或浏览器中,会有点击返回、后退、上一页等按钮实现自己的关闭页面、调整到指定页面、确认离开页面或执行一些其它操作的需求。可以使用 popstate 事件进行监听返回、后退、上一页操作。
具有层级关系的结构中,使用了pointer-events:none 属性将会使当前元素中的事件不会被捕获,从而实现了点穿的效果。而当代码示例中假如top元素具有子元素且显示指定pointer-events属性不为none的时候,top元素注册的事件将会被捕获/冒泡触发
事件对象 event,JavaScript 将事件event作为参数传递,IE中把 event 事件对象作为全局对象 window 的一个属性,获取鼠标在网页中的坐标 = 鼠标在视窗中的坐标 + 浏览器滚动条坐标
何为默认事件?比如 a 会跳转页面,submit 会提交表单等。普通js方法:e.preventDefault()函数。Vue.js方法: .prevent 是vue 的内置修饰符,调用了 event.preventDefault()阻止默认事件
js keyup、keypress和keydown事件都是有关于键盘的事件,当一个按键被pressed 或released在每一个现代浏览器中,都可能有三种客户端事件。
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动、非阻塞式 I/O的模型,使其轻量又高效。比如,文件操作中的fs事件流,网络编程所用到的tcp,http模块等,当你回想自己写的程序后,会发现很多操作都基于事件驱动,Events类。
在写移动端导航的时候经常用到点击按钮出现/隐藏导航条的情况,最常见的方法当然还是前端框架直接调用,省心省力,不易出错;当然还有使用纯JS实现的小代码段。我这里整理了纯CSS实现方式,给需要的人和给自己做个笔记:实现原理利用CSS伪类:target
我做的是一个table的编辑功能,当移入某行的时候展示编辑状态,在移出某行的时候显示的是原始状态,此时遇到一种情况,就是.当mousenter事件触发之后,由于鼠标移动得太快,同一个tr上绑定的mouseleave事件压根儿就没有执行。
js事件传播流程主要分三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。在我们平常用的addEventListener方法中,一般只会用到两个参数,一个是需要绑定的事件,另一个是触发事件后要执行的函数
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!