是否可以判断异步函数当前是否在"program"顶部运行?



我正在尝试做一些涉及全局上下文的事情,知道当前正在运行的函数。

这对于单线程同步函数来说很容易,它们开始运行并在返回时结束运行。

但是异步函数可以弹出到程序的底部,并在完成之前多次爬上来。

let currentlyRunningStack: string[] = [];
function run(id: string, cb: () => any) {
currentlyRunningStack.push(id);
cb()
currentlyRunningStack.shift();
}
// works with synchronous stuff
run("foo", () => {
run("bar", () => console.log("bar should be running"));
console.log("now foo is running");
});
// can it work with asynchronous
run("qux", async () => {
// async functions never run immediately...
await somePromise();
// and they start and stop a lot
});

是否有可能跟踪异步函数当前是否正在运行或当前正在等待某事?


编辑:似乎有类似的东西叫做Zone.js。我猜是由Angular使用的。

  • 类似async_hooks的浏览器?

编辑:根据@Bergi的建议,单词"stack"已更新为"程序"。为澄清

这是可能的,而且有人已经这样做了——angular开发人员,不少于——但是它花费了惊人的5.41Mb!!

https://www.npmjs.com/package/zone.js

这是从一个非常相似的问题:类似于浏览器的async_hooks的东西?

为了与这个问题有所区别,我将在这里回答核心问题:

是的,你可以告诉异步函数何时开始和停止。您可以在项目代码

中看到很多所需的内容。特别地,这个文件似乎处理多填充承诺,尽管我需要更多的时间来验证这就是魔法发生的地方。也许通过一些努力,我可以把它提炼成更容易理解的东西,不需要5.41 Mb来实现。

是的,有可能。

使用运行的上下文,比如互斥锁,由Edgar W. djiskstra提供,堆栈队列,承诺状态和承诺。所有的遗嘱执行人。通过这种方式,您可以跟踪程序中是否有正在运行的函数。您必须实现一个垃圾收集器,以保持互斥锁列表干净,并且需要一个计时器(setTimeout)来验证上下文是否干净。当上下文干净时,您将调用类似回调的函数来结束程序,例如process.exit(0)。上下文指的是整个程序的执行顺序。

将函数转换为带有.then回调函数的promise,在函数内容执行后弹出/清除互斥锁的堆栈,并使用try/catch块抛出、处理或记录错误,为hole程序增加了更多的控制。

setTimeout的引入代表了一个状态机,结合了互斥锁/锁,并引入了一个内存泄漏,您需要跟踪计时器来清除每个函数分配的内存。

这是通过neste try/catch完成的。对它使用setInterval会导致内存泄漏,从而导致缓冲区溢出。

计时器将完成程序的结束,就这样。您可以跟踪函数是否正在运行,并将每个函数注册在同步的中。

以同步方式运行程序/解释器可以避免内存泄漏和竞争条件,并且工作良好。下面是一些代码示例:


const async run (fn) => {
const functionContextExecutionStackLength = functionExecutionStackLength + 1
const checkMutexStackQueue = () => {
if (mutexStack[0] instanceof Promise) {
if (mutex[0].state == "fullfiled") {
mutexStack = mutexStack.split(1, mutexStack.length)
runner.clear()
runner()
}
}
if (mutexStack.length == 0) process.exit(0)
}
// clear function Exection Context
const stackCleaner = setTimeout(1000, (err, callback) => {
if (functionContextExecutionStackLength == 10) {
runner.clear()
}
})
stackCleaner = stackCleaner()
// avoid memory leak on function execution context
if (functionContextExecutionStackLength == 10) {
stackCleaner.clear()
stackCleaner()
}
// the runner
const runner = setTimeout(1, async (err, callback) => {
// run syncronous 
const append = (fn) => mutex.append(util.promisfy(fn)
.then(appendFunctionExectionContextTimes)
.then(checkMutexStackQueue))
// tranaform into promise with callback
const fn1 = () => util.promify(fn)
const fn2 = () => util.promisfy(append)
const orderOfExecution = [fn1, fn2, fn]
// a for await version can be considered
for (let i = 0; i < orderOfExecution.length; i++) {
if (orderOfExecution.length == index) {
orderOfExecution[orderOfExecution.length]()
} else {
try {
orderOfExecution[i]()
} catch (err) {
throw err
console.error(err)
}
}
}
}
}
(() => run())(fn)
在上面的代码中,我们非常重视javascript的异步特性。必要时避免使用,需要时使用。

观察:

  • 一些变量被提交,但这是一个演示代码。
  • 有时你会看到一个变量上下文切换和调用在执行之前,这是由于es模块的特点,读取它的全部和解释它。

相关内容

  • 没有找到相关文章

最新更新