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);
}