简体   繁体   English

是否可以在 jQuery.each() 中使用同步承诺 sleep ?

[英]Is it possible to use a sync promise sleep inside of jQuery.each()?

So basically.所以基本上。 I want to use jQuery's each function within a sync function.我想在同步函数中使用 jQuery 的每个函数。 However, as far as I know.不过,据我所知。 It doesn't work because the each function just checks if the return value is false to break the loop.它不起作用,因为 each 函数只是检查返回值是否为假来中断循环。 It doesn't check if its a promise and then sets it to await for it to be resolved.它不会检查它是否是一个承诺,然后将它设置为等待它被解决。 Is there a simple way to make the each function of jQuery synchronous with promises?有没有一种简单的方法可以使 jQuery 的每个函数与 Promise 同步?

I currently have an alternative which is to create a for loop iterating the elements, but its a bit lengthy to write so I'd like to avoid that if possible.我目前有一个替代方法,即创建一个迭代元素的 for 循环,但编写起来有点冗长,所以如果可能的话,我想避免这种情况。

Here is a fiddle of it: https://jsfiddle.net/3pcvqswn/2/这是一个小提琴: https : //jsfiddle.net/3pcvqswn/2/

function sleep(ms)
{
    return new Promise(resolve => setTimeout(resolve, ms));
}

$(document).ready(function()
{
    (async () =>
  {
    console.log("This method works, but its lengthy to write");
    var elements = $("div");

    for(var index = 0; index < elements.length; index++)
    {
        var el = $(elements.eq(index));

        console.log("The content is: " + el.text());

      await sleep(1000);
        }

    console.log("This method doesn't work, but its easier to write");
    $("div").each(async (index, el) =>
    {
        console.log("The content is: " + $(el).text());

      // doesn't wait
      await sleep(1000);
    });
  })();
});

I decided to go with for of , but a more accurate solution to have both the index and element callback would be我决定使用for of ,但是同时拥有索引和元素回调的更准确的解决方案是

  Object.entries($("div")).forEach(async ([index, el]) =>
  {
    console.log("row ", index, el);
  });

No - jQuery's .each works similarly to forEach .否 - jQuery 的.eachforEach的工作方式类似。 Each callback will be fired off one after the other, and if the callback returns a Promise (such as if it's an async function), it won't be waited for - it works similarly to每个回调都会一个接一个地被触发,如果回调返回一个 Promise(比如它是一个异步函数),它就不会被等待——它的工作原理类似于

callback();
callback();
callback();

Unless something in the callback blocks (which it shouldn't if you're using decent programming practices), nothing asynchronous initialized in the callback can result in further callbacks waiting for that asynchronous action to complete.除非回调中的某些内容(如果您使用体面的编程实践,则不应该这样做),回调中的任何异步初始化都不会导致进一步的回调等待该异步操作完成。

But jQuery objects are iterable, so it's trivial to use a concise for..of to iterate over the elements:但是 jQuery 对象是可迭代的,所以使用简洁的for..of来迭代元素是微不足道的:

 const sleep = ms => new Promise(res => setTimeout(res, ms)); (async () => { for (const elm of $("div")) { console.log("The content is: " + $(elm).text()); await sleep(1000); } })();
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div>text 1</div> <div>text 2</div> <div>text 3</div>

That's not verbose at all IMO.这一点都不冗长 IMO。

In order to use await in a loop, the loop either has to be a for loop (either for..in, for..of, or for(let i = ...), or the loop's iteration mechanism needs to be constructed so that it waits for the last callback to resolve, such as with reduce :为了在循环中使用await ,循环要么必须是for循环(for..in、for..of或for(let i = ...),要么需要构造循环的迭代机制以便它等待最后一个回调解决,例如使用reduce

 const sleep = ms => new Promise(res => setTimeout(res, ms)); [...$("div")].reduce(async (lastProm, elm) => { await lastProm; console.log("The content is: " + $(elm).text()); await sleep(1000); }, Promise.resolve());
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div>text 1</div> <div>text 2</div> <div>text 3</div>


Side note that's barely worth mentioning - I said earlier that using await inside .each won't work旁注几乎不值得一提 - 我之前说过在.each中使用await行不通的

Unless something in the callback blocks (which it shouldn't if you're using decent programming practices)除非回调中的某些内容(如果您使用的是体面的编程实践,则不应该这样做)

If you write an expensive and silly blocking version of sleep which consumes all resources until the next second is reached, it's "possible" to wait inside the loop, but it shouldn't ever be done:如果您编写了一个昂贵且愚蠢的sleep阻塞版本,它会消耗所有资源直到下一秒到达,则“可能”在循环内等待,但不应该这样做:

const sleep = ms => {
  const now = Date.now();
  while (Date.now() - now < ms) {}
}

It's be much better to work with the Promises properly.正确使用 Promise 会好得多。

You can't force $.each to run serially (one after another).你不能强制$.each连续运行(一个接一个)。 It runs the function for each element "simultaneously".它“同时”运行每个元素的函数。 One option is to write your own each function that just performs the longer version you wrote in your question:一种选择是编写自己的each函数, each函数只执行您在问题中编写的较长版本:

const serialEach = async (f, elements) => {
   for(let index = 0; index < elements.length; index++) {
       const el = $(elements.eq(index))

       await f(el)
    }
}

Then you could run it like this:然后你可以像这样运行它:

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms))
}

$(document).ready(() => {
    const elements = $("div")

    serialEach(async (el) => {
        console.log("The content is: " + el.text())

        await sleep(1000)
    }, elements)
})

Note that serialEach returns a promise, so it will return immediately and any code you have after the serialEach call will execute, even while serialEach is iterating over your elements.请注意, serialEach返回一个promise,因此它会立即返回,并且在serialEach调用之后您拥有的任何代码都将执行,即使serialEach正在迭代您的元素。 If you want to wait for that iteration to complete before continuing, you could just await serialEach (and make your $.ready callback async ).如果您想在继续之前等待该迭代完成,您可以只await serialEach (并使您的$.ready回调async )。

I wouldnt advice to use .each for this.我不建议为此使用 .each。 the function gets executed regarless if it's a asynchronous or not.无论是否异步,该函数都会被执行。 But with programming you can be creative.但是通过编程,您可以发挥创造力。

//code

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

let promise = Promise.resolve();
$("div").each((index, el) => {
  promise = promise.then(async () => {
    console.log("The content is: " + $(el).text());

    await sleep(1000);
  });
});

await promise;

//code

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

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