Javascript 函数能否确定该函数的最后一次调用是否在事件循环中同步发生?
假设我有一个函数Javascript 函数能否确定该函数的最后一次调用是否在事件循环中同步发生?,javascript,event-loop,Javascript,Event Loop,假设我有一个函数fn,在不可预测的情况下在别处调用,我希望能够区分函数的连续同步调用和函数的异步调用。即,区分: // synchronous fn(); doSomething(); fn(); 及 如果下一次调用fn是在一个单独的任务(或消息)期间进行的,则相对容易:回调传递了Promise.resolve()。然后将作为一个微任务运行,就在当前(宏任务)完成之前,因此可以在调用函数时检查/设置一个标志,并在微任务中重置它 const fn=(()=>{ 让calledDuringThi
fn
,在不可预测的情况下在别处调用,我希望能够区分函数的连续同步调用和函数的异步调用。即,区分:
// synchronous
fn();
doSomething();
fn();
及
如果下一次调用fn
是在一个单独的任务(或消息)期间进行的,则相对容易:回调传递了Promise.resolve()。然后
将作为一个微任务运行,就在当前(宏任务)完成之前,因此可以在调用函数时检查/设置一个标志,并在微任务中重置它
const fn=(()=>{
让calledDuringThisMessage=false;
返回值(arg)=>{
console.log('fn running',arg);
如果(调用DuringThismessage){
log('Duplicate synchronous call!');
}
calledDuringThisMessage=true;
承诺,决心
.然后(()=>{
calledDuringThisMessage=false;
});
};
})();
fn(1);
fn(2);
设置超时(fn,0,3)代码>我真的希望,这对你有帮助。您可以“注册”函数,以便在调用它们时将它们放入自定义堆栈中
const MY_FUNCTION_STACK = [];
function register(func) {
return function (...args) {
MY_FUNCTION_STACK.push(func);
return func(...args);
}
}
function test1() {
return 1;
}
test1 = register(test1);
test1(); // returns 1
test1(); // returns 1
MY_FUNCTION_STACK; // returns [test1(), test1()]
这不会改变原始函数,因此您可以使用它注册第三方方法。
您还可以添加时间戳或任何有关所需函数的附加信息(稍后按DateTime排序)。
使用此解决方案,您还可以选择是否要向堆栈添加函数调用
- 承诺一开始
- 还是承诺的结束
- 或者只有承诺得到解决
你有完全的控制权
编辑:
如果您只想记录某些函数,则可以使用下面的示例。如果要记录所有函数,可以使用以下代码:
const originalPrototypeCall = Function.prototype.call;
Function.prototype.call = function call(...args) {
MY_FUNCTION_STACK.push(this);
return originalPrototypeCall.bind(this)(...args);
}
请记住,更改系统原型不是一个好的做法,可能会导致许多无法解决的问题。我真的很好奇,是否有一个真实世界的使用案例。您的代码永远不需要知道两个调用是否是同一消息的一部分,除非您正在为事件循环本身编写某种可视化工具。通常,简单的解决方案是对函数进行去抖动或节流。换句话说,如果您无法控制调用fn
的位置,并且有人更改fn(1);fn(2)
至fn(1);setTimeout(()=>fn(2))
,是否希望其行为有所不同?如果不是,那么判断调用是否是同一消息的一部分就没有真正的价值。这主要是理论上的。当我意识到来自整个代码库的复杂的fn
外部调用总是要求在第一次同步调用(可能称之为prepareFn
)之前发生其他事情时,我突然想到了这个想法。我曾考虑过重构,以便在需要时调用fn
内部的prepareFn
,但后来意识到,微任务会让这变得很困难。(是的,我想区分fn(2)
和setTimeout(()=>fn(2))
如果两者前面都是fn(1)
,因为第二个是异步的,而第一个不是)
const originalPrototypeCall = Function.prototype.call;
Function.prototype.call = function call(...args) {
MY_FUNCTION_STACK.push(this);
return originalPrototypeCall.bind(this)(...args);
}