让我从我喜欢异步代码的事实开始。我永远不会在生产中将异步代码包装在同步包装器中,但这仍然是我想学习如何做的事情。我指的是 Node.JS,而不是浏览器。有很多方法可以同步访问异步函数的结果,例如使用child_process.spawnSync或工作器和Atomics。这些方法的问题是:
let prom = Promise.resolve(4);
// It is now impossible (as far as I know) to access the result of prom synchronously
Run Code Online (Sandbox Code Playgroud)
Promise 无法在调用中发送postMessage,因此工作人员无法访问它们并等待它们同步完成或根本无法完成。有人可能会想,为什么不这样做:
let prom = Promise.resolve(4);
prom.then(res => global.result = res);
while (!global.result) {}; // Do nothing
// Once the loop finishes, the result *would* be available
console.log(global.result); // => 4
Run Code Online (Sandbox Code Playgroud)
当然,这是行不通的。事件循环在开始处理 的回调函数之前等待完全执行 while 循环prom.then。这会导致无限循环。所以这让我问,“是否有一个同步任务必须非正常执行才能等待承诺?”
编辑
顺便说一句,我完全理解async/await。如果我使用 Node.JS 模块,那么我可以这样做:
let resolved = await prom;
Run Code Online (Sandbox Code Playgroud)
或者,如果我不是,我可以将整个脚本包装在一个 …
当鼠标触发单击事件时,它的行为符合预期:
首先,侦听器 1 被推入堆栈,并在微任务队列(或作业队列)中对 Promise 1 进行排队。当侦听器 1 弹出时,堆栈变空。Promise 1 回调在侦听器 2 之前执行(侦听器 2 在任务队列(或回调队列)中等待)。在 Promise 1 回调弹出后,侦听器 2 被压入堆栈。因此输出为:
侦听器 1 微任务 1 侦听器 2 微任务 2
但是,当通过 JavaScript 代码触发点击时,其行为会有所不同:
即使在 click() 函数完成之前,回调也会被推入堆栈(即调用堆栈不为空)。这里的输出是:
监听器 1 监听器 2 微任务 1 微任务 2
这是代码:
window.onload = function(){
document.getElementById("myBtn").addEventListener('click', () => {
Promise.resolve().then(() => console.log('Microtask 1'));
console.log('Listener 1');
} );
document.getElementById("myBtn").addEventListener('click', () => {
Promise.resolve().then(() => console.log('Microtask 2'));
console.log('Listener 2');
} );
}
function clickB(){
document.getElementById("myBtn").click();
}Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>
<button id="myBtn">Manual …Run Code Online (Sandbox Code Playgroud)我对 Node.js 文档的以下段落感到困惑。
setImmediate()与setTimeout()...定时器的执行顺序将根据调用它们的上下文而变化。如果两者都是从主模块内部调用的,那么计时将受到进程性能的约束(这可能会受到计算机上运行的其他应用程序的影响)。
例如,如果我们运行以下不在 I/O 周期(即主模块)内的脚本,则两个计时器的执行顺序是不确定的,因为它受到进程性能的约束:
接下来显示以下示例
// timeout_vs_immediate.js
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
Run Code Online (Sandbox Code Playgroud)
$ node timeout_vs_immediate.js
timeout
immediate
$ node timeout_vs_immediate.js
immediate
timeout
Run Code Online (Sandbox Code Playgroud)
我不明白是什么导致结果不确定。由于该timers阶段发生在该check阶段之前,因此安排的回调不应该setTimeout总是在安排的回调之前执行吗setImmediate?我认为事件循环中的阶段顺序不会因为上下文切换或其他原因而改变。
该文件还指出
但是,如果在一个 I/O 周期内移动这两个调用,则始终先执行立即回调:
好的,但是所谓的“I/O 周期”与主模块有何不同?
我知道有很多相关的问题,但所有答案都只是通过引用文档来陈述这一事实,而没有解释非确定性在哪里发挥作用,所以我认为这不是重复的。
这是节点事件循环。
\n \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x8c\xe2\x94\x80>\xe2\x94\x82 timers \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n\xe2\x94\x82 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x82 \xe2\x94\x82 pending callbacks \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n\xe2\x94\x82 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x82 \xe2\x94\x82 idle, prepare \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x82 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90 \xe2\x94\x82 incoming: \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x82 poll \xe2\x94\x82<\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xa4 connections, \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98 \xe2\x94\x82 data, etc. \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n\xe2\x94\x82 \xe2\x94\x82 check \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n\xe2\x94\x82 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\xa4 close callbacks \xe2\x94\x82\n \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\nRun Code Online (Sandbox Code Playgroud)\n我知道 Node 使用 V8 JS 引擎,并且我了解到V8 有自己的事件循环,嵌入器可以自由替换或扩展。例如,在 Chrome 中,有一个宏任务和一个微任务队列(微任务队列的优先级高于宏任务队列),一旦主线程的调用堆栈为空,事件循环就会从这些队列中推送回调。
\n您可以使用该函数手动将微任务排队到微任务队列中 queueMicrotask。
我也尝试过在 Node 中使用这个函数并且它有效。我的问题是,微任务在事件循环中排队的位置在哪里?他们在哪个阶段排队?他们是否有一个特定的阶段,或者是否与其他类型的回调混合在一起?
\n我尝试了这段代码来了解 Node 事件循环中优先级的内容:
\nconst hello_world =() => {\n console.log("Hello World 2");\n};\n\nqueueMicrotask(hello_world);\n\nsetTimeout(\n () …Run Code Online (Sandbox Code Playgroud) 我正在使用epoll/devpoll/kqueue/poll/select(包括windows-select)设计异步套接字IO的事件循环.
我有两个执行IO操作的选项:
非阻止模式,在EAGAIN上进行调查
轮询模式:轮询然后执行
对我来说,在普通模式下使用时,首先需要较少的系统调用,特别是对于写入套接字(缓冲区非常大).此外,它似乎可以减少"选择"执行次数的开销,尤其是当你没有像epoll/devpoll/kqueue那样可以扩展的东西时,它会很好.
问题:
注意:请不要建议使用现有的event-loop/socket-api实现
在搞乱多线程,回调,win32 api功能以及其他麻烦的问题时,我收到了一个想法事件.(呵呵呵)
如果,而不是(设计一个类时或静态)回调函数定义一个全球性的,而不是我指派DefWindowProc为lpfnWndProc注册窗口类的时候,然后运行在一个单独的线程整个事件循环?
这样我就不必在类中实现回调this时解决问题,
并且主线程的执行继续进行,让你从那个被遗忘的循环中解放出来,允许你做任何事情,甚至打开另一个窗口(耶!)
"正常"方式:
LRESULT CALLBACK WndProc(...)
{
... // process event information
return DefWindowProc(...);
}
int CALLBACK WinMain(...)
{
... // initialize whatever needs initializing :)
WNDCLASSEX wc;
...
wc.lpfnWndProc = WndProc;
... // register the class, create the window, etc...
MSG msg;
while(GetMessage(&msg, 0, 0, 0) != 0)
{
... // TranslateMessage(&msg) if you want/need it
DispatchMessage(&msg); // dispatches the message to WndProc
}
return static_cast<int>(msg.wParam);
}
Run Code Online (Sandbox Code Playgroud)
我新发现的令人敬畏的方式:
DWORD …Run Code Online (Sandbox Code Playgroud) 假设我在Node.js中有一个异步函数,基本上是这样的:
var addAsync = function (first, second, callback) {
setTimeout(function () {
callback(null, first + second);
}, 1 * 1000);
};
Run Code Online (Sandbox Code Playgroud)
现在我当然可以以异步方式调用此函数:
addAsync(23, 42, function (err, result) {
console.log(result); // => 65
});
Run Code Online (Sandbox Code Playgroud)
我想知道的是你是否能以某种方式同步调用这个函数.为此,我想要一个包装函数sync,它基本上做了以下事情:
var sync = function (fn, params) {
var res,
finished = false;
fn.call(null, params[0], params[1], function (err, result) {
res = result;
finished = true;
});
while (!finished) {}
return res;
};
Run Code Online (Sandbox Code Playgroud)
然后,我可以addAsync通过这种方式调用它来同步运行:
var sum = sync(addAsync, [23, 42]);
Run Code Online (Sandbox Code Playgroud)
注意:当然你不会使用params[0]和 …
我的Qt应用程序的主窗口是一个普通的QMainWindow子类.在那个窗口我有几个按钮; 每个clicked插槽的信号都连接自己的插槽,每个插槽创建一个不同的插槽QDialog:
void onButtonA_clicked()
{
MyADialog* dialog = new MyADialog(this);
dialog->exec();
delete dialog;
}
Run Code Online (Sandbox Code Playgroud)
我一直在读这篇文章:https://wiki.qt.io/Threads_Events_QObjects#Events_and_the_event_loop和作者说
你永远不应该阻止事件循环
哪个让我担心; exec是一个阻塞函数,所以根据他所说的(他的例子Worker::doWork做了很多工作,需要一些时间来完成)我的代码阻止了事件循环,但我没有注意到任何暗示这一点; 相反,主窗口似乎表现正常,并且当我更改代码以使用该show()方法时没有区别.
我阻止了事件循环吗?我应该在这里使用不同的方法吗?
我写了这个辅助功能扩展:
这适用于Gnome Shell v3.14和v3.16中的假设,但不适用于v3.10.它显示了重新启动它之后唯一的初始键盘修饰符状态,并且在此之后永远不会更新它.
这里是完整的代码:
const St = imports.gi.St;
const Mainloop = imports.mainloop;
const Main = imports.ui.main;
const Gdk = imports.gi.Gdk
let button, label, keymap;
function _update() {
let symbols = "????????";
let state = keymap.get_modifier_state();
label.text = " ";
for (var i=0; i<=8; i++ ) {
if (state & 1<<i) {
label.text += symbols[i];
} else {
//label.text += "";
}
}
label.text += " ";
}
function init() {
button = new St.Bin({ style_class: 'panel-button',
reactive: …Run Code Online (Sandbox Code Playgroud) 看看下面的代码:
var fs = require('fs');
var pos = 0;
fs.stat(__filename, function() {
console.log(++pos + " FIRST STAT");
});
fs.stat(__filename, function() {
console.log(++pos + " LAST STAT");
});
setImmediate(function() {
console.log(++pos + " IMMEDIATE")
})
Run Code Online (Sandbox Code Playgroud)
当我执行此代码时,将显示以下结果:
正如Node.js 文档所解释的那样,setImmediate在I/O回调之后执行,但是在这个例子中,setImmediate正在I/O回调之前执行,我错过了什么吗?
event-loop ×10
javascript ×6
node.js ×5
asynchronous ×3
c++ ×3
synchronous ×2
blocking ×1
c ×1
callback ×1
callstack ×1
dom-events ×1
gjs ×1
gnome ×1
gtk ×1
nonblocking ×1
promise ×1
qeventloop ×1
qt ×1
winapi ×1
windows ×1