简体   繁体   English

如何防止从特定承诺中调用函数?

[英]How do I prevent a function from being called from within a specific promise?

I'm working on a library and I'd like to prevent users from calling a specific function in order to prevent infinite loops.我正在开发一个库,我想阻止用户调用特定函数以防止无限循环。 Usually I'd go about doing it like this:通常我会这样做:

let preventFooCalls = false;

function fireUserCallbacks() {
    preventFooCalls = true;

    // Fire callbacks of the user here...

    preventFooCalls = false;
}

function foo() {
    if (preventFooCalls) throw Error();

    // Run the content of foo() ...
    // It will probably call fireUserCallbacks() at some point
}

However, if fireUserCallbacks is async, this method is not possible.但是,如果fireUserCallbacks是异步的,则无法使用此方法。 It might be called multiple times, and with async user callbacks, preventFooCalls is not guaranteed to have the correct value.它可能会被多次调用,并且对于异步用户回调,不能保证preventFooCalls具有正确的值。 For instance:例如:

let preventFooCalls = false;

async function fireUserCallbacks() {
    preventFooCalls = true;

    // Fire callbacks of the user here one of which being:
    await new Promise(r => setTimeout(r, 1000));

    preventFooCalls = false;
}

// Then when doing:
fireUserCallbacks();
foo(); // This will throw even though it's being called from outside fireUserCallbacks()

How can I detect if code is running from within a specific promise?如何检测代码是否在特定承诺中运行? The only thing I can think of is new Error().stack , but oof that sounds like a terrible way to do it.我唯一能想到的就是new Error().stack ,但这听起来很糟糕。


Some context一些上下文

The reason why I want this is because I'm working on a part of a library that takes care of loading assets.我想要这个的原因是因为我正在处理负责加载资产的库的一部分。 Some of these assets might contain other assets with the possibility of infinite recursion.其中一些资产可能包含具有无限递归可能性的其他资产。 In order to handle recursion I have another function that I want users to call instead.为了处理递归,我有另一个我希望用户调用的函数。 Therefore I want to warn users when they call foo() from within one of the fireUserCallbacks() callbacks.因此,当用户从fireUserCallbacks()回调之一中调用foo()时,我想警告用户。 While this will only be an issue when assets actually contain infinite loops, I'd rather block the usage of foo() completely to prevent unexpected hangs due too infinite loops.虽然这只会在资产实际包含无限循环时成为一个问题,但我宁愿完全阻止foo()的使用,以防止由于无限循环而导致意外挂起。

Maintain a queue and a set.维护一个队列和一个集合。 The queue contains pending requests.队列包含挂起的请求。 The set contains pending requests, requests in progress, and successfully completed requests.该集合包含待处理的请求、进行中的请求和成功完成的请求。 (Each item would include the request itself; the request's status: pending, processing, complete; and possibly a retry counter.) (每个项目都包括请求本身;请求的状态:待处理、处理、完成;可能还有一个重试计数器。)

When request is made, check if it is in the set.提出请求时,检查它是否在集合中。 If it is in the set, it was already requested and will be processed, is being processed, or was processed successfully and is already available.如果它在集合中,则它已经被请求并且将被处理、正在被处理或被成功处理并且已经可用。 If not in the set, add it to both the set and the queue, then trigger queue processing.如果不在集合中,则将其添加到集合和队列中,然后触发队列处理。 If queue processing is already running, the trigger is ignored.如果队列处理已在运行,则忽略触发器。 If not, queue processing starts.如果不是,则队列处理开始。

Queue processing pulls requests off the queue, one by one, and processes them.队列处理将请求逐一拉出队列,并对其进行处理。 If a request fails, it can either be put back onto the queue for repeat attempts (a counter can be included in the item to limit retries) or it can be removed from the set so it can be requested again later.如果请求失败,可以将其放回队列以进行重复尝试(可以在项目中包含一个计数器以限制重试),也可以将其从集合中删除,以便稍后再次请求。 Queue processing ends when the queue is empty.当队列为空时,队列处理结束。

This avoids recursion and unnecessary repeat requests.这避免了递归和不必要的重复请求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM