是否可以在 jQuery.each() 内部使用同步承诺睡眠?

Joh*_*ohn 5 javascript each jquery asynchronous promise

所以基本上。我想在同步函数中使用 jQuery 的每个函数。不过,据我所知。它不起作用,因为每个函数只是检查返回值是否为 false 以打破循环。它不会检查它是否是一个承诺,然后将其设置为等待它得到解决。有没有一种简单的方法可以使 jQuery 的每个函数与 Promise 同步?

我目前有一个替代方案,即创建一个迭代元素的 for 循环,但写起来有点长,所以我想尽可能避免这种情况。

这是它的一个小提琴: 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);
    });
  })();
});
Run Code Online (Sandbox Code Playgroud)

我决定使用for of,但是同时具有索引和元素回调的更准确的解决方案是

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

Cer*_*nce 4

否 - jQuery 的.each工作方式与forEach. 每个回调都会被一个接一个地触发,如果回调返回一个 Promise(例如它是一个异步函数),则不会等待它 - 它的工作原理类似于

callback();
callback();
callback();
Run Code Online (Sandbox Code Playgroud)

除非回调中的某些内容阻塞(如果您使用正确的编程实践,则不应阻塞),否则回调中初始化的任何异步操作都不会导致进一步的回调等待该异步操作完成。

但 jQuery 对象是可迭代的,因此使用简洁的方法for..of来迭代元素是很简单的:

callback();
callback();
callback();
Run Code Online (Sandbox Code Playgroud)
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);
  }
})();
Run Code Online (Sandbox Code Playgroud)

在我看来,这一点也不冗长。

为了await在循环中使用,循环必须是一个for循环(for..in、for..of 或 for(let i = ...)),或者需要构造循环的迭代机制,以便它等待最后一个回调解析,例如reduce

<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>
Run Code Online (Sandbox Code Playgroud)
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());
Run Code Online (Sandbox Code Playgroud)


旁注几乎不值得一提 - 我之前说过使用awaitinside.each不起作用

除非回调中的某些内容阻塞(如果您使用良好的编程实践,则不应该发生这种情况)

如果您编写一个昂贵且愚蠢的阻塞版本,其sleep消耗所有资源直到到达下一秒,则“可能”在循环内等待,但不应该这样做:

const sleep = ms => {
  const now = Date.now();
  while (Date.now() - now < ms) {}
}
Run Code Online (Sandbox Code Playgroud)

正确地使用 Promise 会更好。