承诺与异步等待行为JavaScript。并发模式

发布于 2025-01-23 13:01:23 字数 1926 浏览 2 评论 0原文

我正在尝试避免异步函数的并发,以便等待该功能的第一个调用,然后才能再次调用相同的函数:

const disallowConcurrency = (fn) => {
  let inprogressPromise = Promise.resolve();

  return async(...args) => {
    await inprogressPromise;
    inprogressPromise = inprogressPromise.then(() => fn(...args));
  };
};

const initCmp = async(arg) => {
  return new Promise((res) => {
    console.log('executed');
    setTimeout(() => res(console.log(arg)), 1000);
  });
};
const cmpConcurrentFunction = disallowConcurrency(initCmp);
cmpConcurrentFunction('I am called 1 second later');
cmpConcurrentFunction('I am called 2 seconds later');

因此,在这里,我创建了一个带有承诺的封闭,因为一个值传递给了内部函数。 返回函数将等待上一个呼叫(在第一次运行中,这是一个已解决的承诺),将会分配给inprogressPromise 然后由 >在这种情况下将成为由initcmp函数返回的新承诺。因此,下次我们调用该功能时,它将等待上一个功能。至少这就是我的理解方式。我做对了吗?

但是,我不明白,如果我删除等待InProgressPromise例如这样的情况,为什么会继续工作:

    const disallowConcurrency = (fn) => {
  let inprogressPromise = Promise.resolve();

  return async (...args) => {
    inprogressPromise = inprogressPromise.then(() => fn(...args));
  };
};

因此,等待不需要?为什么?

此外,我期望这会起作用:

 const disallowConcurrency = (fn) => {
  let inprogressPromise = Promise.resolve();

  return async (...args) => {
    await inprogressPromise;
    inprogressPromise = fn(...args);
  };
};

因为我认为首先要等待先前的承诺做出来,然后我会打电话给inprogresspromise上的返回承诺。

但是它不起作用,这两个功能同时被调用。

有人可以澄清我在这里发生了什么吗?

如果您尝试代码,您会发现第二个呼叫

cmpConcurrentFunction("I am called 2 seconds later")

将等待第一个承诺做出。

基本上,我编写了一个节点软件包,该节点软件包通过NPM在Web应用程序中导入到浏览器中。 该节点软件包库具有具有一些异步代码的初始函数,并且可以在代码的不同部分中多次调用。 例如,如果被称为第二次,我想确保在尝试再次执行代码之前将执行第一个执行。

但是我的观点是试图了解为什么该代码有效,以及为什么我使用最后一个版本

谢谢!

i'm trying to avoid concurrency of a async function in order to wait for the first call of this function to be finished before i can call it again the same function :

const disallowConcurrency = (fn) => {
  let inprogressPromise = Promise.resolve();

  return async(...args) => {
    await inprogressPromise;
    inprogressPromise = inprogressPromise.then(() => fn(...args));
  };
};

const initCmp = async(arg) => {
  return new Promise((res) => {
    console.log('executed');
    setTimeout(() => res(console.log(arg)), 1000);
  });
};
const cmpConcurrentFunction = disallowConcurrency(initCmp);
cmpConcurrentFunction('I am called 1 second later');
cmpConcurrentFunction('I am called 2 seconds later');

So here i'm creating a closure with a promise as a value passed to the inner function.
The return function will wait for the previous call ( in the first run it's a resolved Promise ) and the will assign to inprogressPromise the promise returned by the then which in this case will be a new Promise returned by the initCmp function. So next time we call the function it will wait for the previous one to be done. At least this is how i'm understanding it. Did i get it right?

But i don't understand why this keeps working if i remove the await inprogressPromisefor example like this :

    const disallowConcurrency = (fn) => {
  let inprogressPromise = Promise.resolve();

  return async (...args) => {
    inprogressPromise = inprogressPromise.then(() => fn(...args));
  };
};

So the await is not necessary? Why?

Further more i was expecting this to work :

 const disallowConcurrency = (fn) => {
  let inprogressPromise = Promise.resolve();

  return async (...args) => {
    await inprogressPromise;
    inprogressPromise = fn(...args);
  };
};

Because i was thinking that first i'm awaiting for the previous promise to be done and then i would call and assign the returned promise on the inprogressPromise.

But it's not working and the two functions are called at the same time.

Can someone clarify me what's going on here?

If you try the code you will see that the second call

cmpConcurrentFunction("I am called 2 seconds later")

will wait for the first promise to be done.

Basically i have written a node package that gets imported into the browser in a web app through npm.
This node package library has an init function that has some async code and can be called multiple time in different part of the code.
If is called a second time for example i want to be sure that the first execution will be done before trying to execute the code again.

But my point is trying to understand why that code works and why it doesn't if i use the last version

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

水水月牙 2025-01-30 13:01:23

要回答您的问题,请首先尝试解释您的代码的工作原理。

了解您的代码如何工作

以下步骤说明您的代码执行:

  1. 脚本执行start

  2. 呼叫disallowCurrency函数,将initcmp作为参数传递。 cmpConcurrentFunction被分配了disallowCurrency的返回值函数

  3. call cmpconcurrentFunction首次传递'我被称为1第二个'作为参数。在此调用期间,InProgressPromise是由Promise.resolve()返回的解决的承诺。等待它暂停函数执行。

  4. 呼叫第二次CMPConcurrentFunction,以'传递给我2秒钟后'作为参数。在第二个调用中,inprogressPromise仍然是由Promise.resolve()返回的解决的承诺。等待它暂停函数执行。

  5. 同步执行脚本在此处结束。事件循环现在可以开始处理微型任务队列

  6. 恢复cmpconcurrentfunction的首次调用而暂停的函数被恢复,调用 then() 方法通过Promise.resolve()inprogressPromise的值通过分配给它的新承诺来更新inprogresspromise.then(...)

  7. 函数由于第二次调用<<代码> CMPConcurrentFunction 已恢复。从步骤6开始,我们知道InProgressPromise现在是由inprogressPromise.then(...)返回的承诺。因此,在其上调用然后调用(),我们只是创建一个前景链,在步骤6中创建的承诺链结束时添加新的then()方法调用。

    在这一点上,我们有一个看起来像这样的链:

      inprogresspromise
      。
      。 
     
  8. 在 IS initcmp函数。调用initcmp设置一个计时器,该计时器可以解决Promise initcmp返回1秒钟后返回。 1秒钟后解决承诺时,'我被称为1秒钟后'在控制台上记录。

  9. 当第一个调用initcomp函数在第一个然后解决方法的回调函数时,解决了第一个然后方法。这导致了第二个然后方法的回调功能的调用。这再次调用initcomp函数,然后返回一个新的承诺,该诺言在另外1秒钟后得到解决。

这说明了为什么您看到'我被称为2秒钟后'在2秒后登录在控制台上。


现在回答您的问题:

,但我不明白,如果我删除等待
InProgressPromise

等待InProgressPromise在您的代码中没有其他目的,只需停止调用cmpconcurrentfunction函数。这两个调用都在等待与Promise.resolve()返回的相同承诺。

所以不需要等待吗?为什么?

因为您在控制台上看到的输出不是因为等待,而是由于cmpconcurrentfunction功能。

更重要的是,我期望这能起作用:

  const diSallawalCurrency =(fn)=&gt; {   
  让InProgressPromise = Promise.resolve();

  返回异步(... args)=&gt; {
    等待InprogressPromise;
    InProgressPromise = fn(... args);   
  }; 
};
 

上面的代码无法作为您的原始代码可行,因为现在未构建了Promise链,这是您原始代码产生的输出的关键。

通过此实现disallowCurrency,您的代码将被执行,如下所述:

  1. 呼叫cmpconcurrentfunction函数,传递'我被称为1秒钟'作为参数


  2. 等待inprogresspromise暂停函数执行

  3. 第二次cmpconcurrentFunction 第二次cmpconcurrentfunction ,在中传递'我被称为2秒后将'作为参数称为一个参数


  4. /code

    等待inprogressPromise暂停该功能执行功能执行。此时,cmpconcurrentfunction的两个调用都被暂停,并且两个功能调用都在等待相同 由于调用promise.resolve.resolve()的承诺。 /代码>。


    这是这里的关键点:cmpconcurrentfunction函数的两个调用都在等待相同Promise> Promise.resolve()创建的 Promise 。为什么两个召唤都在等待同样的承诺?因为在之前第二次调用了cmpconcurrentFunction cmpconcurrentfunction的第一个调用被恢复并调用initcomp函数

  5. 恢复cmpConcurrentFunction的第一个调用,调用initcomp函数,然后将其返回值分配给inprogressProgromise

    调用initcomp函数设置了一个计时器,该计时器可以解决Promise initcomp函数返回1秒钟后返回

  6. 恢复cmpconcurrentfunction之后的第二个调用,调用initcomp函数并将其返回值分配给inprogressPromise,覆盖inprogressPromise的当前值,这是第一个调用返回的承诺initcomp函数。

    调用initcomp函数设置了一个计时器,该计时器可以解决Promise initcomp函数返回1秒钟后返回

在此点1秒后返回,initcomp函数已调用两次,设置在两个单独的计时器上,分别解决各自的承诺。

总结disallyCurrency函数的原始实现之间的差异,这是在原始实现中,您有一个承诺链,该链可以顺序解决承诺,而在第二个实现中,您有两个单独的承诺(不依赖彼此),并且每次1秒钟后都可以解决。

To answer your questions, let me first try to explain how your code is working.

Understanding how your code works

Following steps explain the execution of your code:

  1. Script execution start

  2. Call disallowConcurrency function, passing in the initCmp as an argument. cmpConcurrentFunction is assigned the return value of disallowConcurrency function

  3. Call cmpConcurrentFunction for the first time, passing in 'I am called 1 second later' as an argument. During this invocation, inprogressPromise is a resolved promise returned by Promise.resolve(). Awaiting it pauses the function execution.

  4. Call cmpConcurrentFunction for the second time, passing in 'I am called 2 seconds later' as an argument. During this second invocation, inprogressPromise is still a resolved promise returned by Promise.resolve(). Awaiting it pauses the function execution.

  5. Synchronous execution of script ends here. Event loop can now start processing the micro-task queue

  6. Function paused as a result of first invocation of cmpConcurrentFunction is resumed, calling then() method on the promise returned by Promise.resolve(). The value of the inprogressPromise is updated by assigning it a new promise returned by inprogressPromise.then(...)

  7. Function paused as a result of second invocation of cmpConcurrentFunction is resumed. From step 6, we know that inprogressPromise is now a promise returned by inprogressPromise.then(...). So, calling then() on it, we are simply creating a promise chain, adding a new then() method call at the end of the promise chain created in step 6.

    At this point, we have a chain that looks like this:

    inProgressPromise
      .then(() => fn('I am called 1 second later'))
      .then(() => fn('I am called 2 seconds later')) 
    
  8. Callback function of the first then method is called, which in turn calls the fn argument, which is initCmp function. Calling initCmp sets up a timer that resolves the promise initCmp returns after 1 second. When the promise is resolved after 1 second, 'I am called 1 second later' is logged on the console.

  9. When the promise returned by the first call to initComp function in the callback function of first then method, is resolved, it resolves the promise returned by the first then method. This leads to the invocation of the callback function of the second then method. This again calls the initComp function, which then returns a new promise that is resolved after another 1 second.

This explains why you see 'I am called 2 seconds later' logged on the console after 2 seconds.


Now answering your questions:

But i don't understand why this keeps working if i remove the await
inprogressPromise

await inprogressPromise serves no purpose in your code other than pausing the calls to cmpConcurrentFunction function. Both calls await the same promise that is returned by Promise.resolve().

So the await is not necessary? Why?

Because the output you see on the console is not because of await, but because of the promise chain (step 7 above) that is constructed as a result of two invocations of the cmpConcurrentFunction function.

Further more i was expecting this to work :

const disallowConcurrency = (fn) => {   
  let inprogressPromise = Promise.resolve();

  return async (...args) => {
    await inprogressPromise;
    inprogressPromise = fn(...args);   
  }; 
};

The above code doesn't works as your original code because now the promise chain isn't constructed which is key to the output your original code produces.

With this implementation of disallowConcurrency, your code is executed as explained below:

  1. Call cmpConcurrentFunction function, passing in 'I am called 1 second later' as an argument

  2. Awaiting inprogressPromise pauses the function execution

  3. Call cmpConcurrentFunction for the second time, passing in 'I am called 2 seconds later' as an argument

  4. Awaiting inprogressPromise pauses the function execution. At this point, both invocations of cmpConcurrentFunction are paused and both function invocations are awaiting the same promise that was created as a result of calling Promise.resolve().

    This is the key point here: both invocations of cmpConcurrentFunction function are awaiting the same promise that was created by Promise.resolve(). Why are both invocations awaiting the same promise? Because the cmpConcurrentFunction is invoked for the second time before the first invocation of cmpConcurrentFunction is resumed and calls the initComp function

  5. Resume the first invocation of cmpConcurrentFunction, call the initComp function and assign its return value to inprogressPromise.

    Calling initComp function sets up a timer that resolves the promise initComp function returns after 1 second

  6. Resume the second invocation of cmpConcurrentFunction, call the initComp function and assign its return value to inprogressPromise, overwriting the current value of inprogressPromise which is the promise returned by the first call to initComp function.

    Calling initComp function sets up a timer that resolves the promise initComp function returns after 1 second

At this point, initComp function has been invoked twice, setting up two separate timers that resolve their respective promise after 1 second each.

To summarize the differences between the original implementation of disallowConcurrency function and this one is that in the original implementation, you have a promise chain which resolves the promises sequentially whereas in the second implementation, you have two separate promises (that don't depend on each other) and they are resolved after 1 second each.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文