将 promise 包装到 setTimer() 中而不是有什么意义?

what's the point of wrapping promise into setTimer() and not?

提问人:Kondaveti Charan 提问时间:5/17/2023 最后编辑:Kondaveti Charan 更新时间:5/18/2023 访问量:101

问:

promise 没有 setTimeout()

console.log('Prmoise start');
const lotteryPromise = new Promise(function (resolve, reject) {
   if(Math.random() >= 0.5) {
      resolve('You won the lottery');
   } else {
      reject(new Error('You lost your money'));
   }
});
 
lotteryPromise.then(res => console.log(res)).catch(err => console.error(err));
console.log('Promise end');

promise 和 setTimeout()

    console.log('Prmoise start');
    const lotteryPromise = new Promise(function (resolve, reject) {
    setTimeout( () => {
       if(Math.random() >= 0.5) {
          resolve('You won the lottery');
       } else {
          reject(new Error('You lost your money'));
       }
       },2000);
    });
     
    lotteryPromise.then(res => console.log(res)).catch(err => console.error(err));
    console.log('Promise end');

我不明白 promise 中 setTimeout() 包装的用法?即使没有 setTimeout() wapping,promise 也会以异步方式执行,即它被添加到 eventQueue 中?是 SetTimeout 只是延迟了代码执行,还是我遗漏了什么?顺便说一句,我知道调用堆栈、微任务和回调队列是如何工作的......

JavaScript 异步 settimeout asynccallback

评论

1赞 Jaromanda X 5/17/2023
在您的代码中差异约为 2 秒 - 请注意,这毫无意义,因为当您控制台 .log 时,Promise 尚未解析,无论哪种情况Promise.end
0赞 ruud 5/17/2023
正如您所假设的那样,setTimeout 只是延迟了代码。
0赞 d.k 5/17/2023
让我们等待@T.J.Crowder的回答。我对这种行为有所了解,但觉得不够权威,无法回答这个问题
0赞 Keith 5/17/2023
Even without the timer wrap the promise is asynchronously executing right ?不。。它们只是在下一个宏任务之前排队运行。事实上,如果浏览器没有机会执行另一个宏任务,它甚至会像同步代码一样挂起浏览器。
0赞 Kondaveti Charan 5/18/2023
@Keith,传递到队列中的代码不是异步的吗?还回答我,默认情况下js中的承诺是异步的吗?

答:

-2赞 Dev Gajjar 5/17/2023 #1

Promise.resolve 调度微任务,setTimeout 调度宏任务。微任务在运行下一个宏任务之前执行。

评论

0赞 Jaromanda X 5/17/2023
但代码从不使用哪个是实际函数Promise.resolve
0赞 Syed Faris Ahmed 5/17/2023 #2

通过向代码添加计时器,可以进一步确认 promise 中的代码是异步运行的。这只是为了模拟异步操作(如获取数据)的真实示例的行为。 它会等待 2 秒钟,然后执行您的操作并在之后解决。

3赞 Quentin 5/17/2023 #3

你正在向后解决这个问题。你应该问:在没有setTimeout的情况下使用promise有什么意义?

promise 的目的是以标准方式管理异步代码。

构造函数的目的是为异步代码创建一个 promise,该代码本身不使用 promise。new Promise


在第一个代码块中,传递给的函数没有任何异步内容。这是一个毫无意义的承诺。Promise()

在你的第二个代码块中,它是异步的,但你无法知道它何时完成(除了修改你传递给它的回调)。与它一起使用允许您在完成后使用 promise 对象执行某些操作setTimeoutnew PromisesetTimeout

也就是说,对于这个例子,根本没有明显的理由使用或承诺。它完全是为了演示 promise 的工作原理,而不是一个实际的例子,说明何时应该使用 promise 或超时。setTimeout

评论

0赞 d.k 5/17/2023
我不会说第一个例子毫无意义。它是异步的,因为根据定义,Promise 在另一个队列中运行,但它与另一个队列不同,如前所述,setTimeout 和其他一些工具使用@DevGajjar。虽然它类似于 setTimeout(func, 0),但它仍然不是 setTimeout 调用,并且会更早运行
3赞 Keith 5/17/2023
@DmitryKoroliov号Promise 不会被添加到异步队列中,这可能是您感到困惑的地方。如果他们这样做,性能将是一个巨大的问题。发生什么 promise 会排队,当下一个 EVENT 循环发生时,这些 promise 会被执行。尝试创建一个带有 promise 的无限循环,而不允许浏览器处理异步事件,例如计时器,您会看到浏览器实际上会挂起。
0赞 d.k 5/17/2023
@Keith您能否快速解释一下异步一词的含义?因为我总是假设它是添加到 2 个队列中的任何一个的任何东西,即不会立即执行。我的意思是,示例 1 中对 Promise 调用的回调不会立即执行,因此可能有一个点以这种方式使用 Promise,因为可能有一个点调用 setTimeout(f, 0)
0赞 d.k 5/17/2023
@Keith对不起,但我不明白你对无限循环的意思,即它与 setTimeout 情况有何不同?如果我有一个无限循环并在其中调用 setTimeout,那么,我敢肯定,也不会执行任何回调。那么它是否使 setTimeout 也不是异步的呢?老实说,我很困惑
1赞 Keith 5/17/2023
@DmitryKoroliov 不确定最好的解释方式,我可能会敲出一个简单的片段,它展示了使用承诺创建一个无限循环,一个有效,一个无效。然后也许可以解释其中的区别。
2赞 Keith 5/17/2023 #4

承诺的一个略微错过的概念是,有异步。但实际上只有一个合约,然后它被放入一个队列中,该队列将在下一个事件循环之前进行处理。对于编写异步代码非常有用,比回调好得多。

下面是一个包含 2 个 promise 的简单示例,1 个 promise 不做任何异步操作,另一个执行简单的异步睡眠。异步休眠非常重要,因为这允许浏览器处理下一个事件循环。如果您取消此睡眠并重新运行,请观察浏览器将如何挂起。

请注意:准备好使用 Chrome 的任务管理器来杀死 浏览器 TAB 键,当您注释掉 .await sleep(1)

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

async function nothingProm() {
  // a promise that does no async stuff
}

//this infinate loop will not hang the browser
async function test() {
  while (true) {
    await nothingProm();
    await sleep(1);  //remove this for HANG!!!     
  }
}

test();

现在,在上面,为什么删除该睡眠会导致浏览器挂起,这似乎很奇怪。

浏览器使用一种称为事件循环的东西,它负责获取鼠标点击、计时器等内容,并将它们发送给侦听器。这与协作式多任务操作系统的工作方式非常相似,比如 Window 3.11。

因此,在浏览器 TAB 中,将有一个事件循环运行,执行类似 ->

while (running) {
  var message = getNextMessage();
  dispatchMessage(message);
}

上面的内容将有效地等待某些事件、计时器、鼠标移动等。因此,它不会浪费 CPU 资源,即使认为它处于这个紧密的循环中。getNextMessage

那么,这与你可能会问的承诺有什么关系呢?嗯,这个位是进来的地方,不像一个计时器,浏览器可以从中调度,基本上卡在一个队列中,在处理下一个之前被排空。microtaskmacrotaskmacrotask

while (running) {
  var message = getNextMessage();  // (1)
  dispatchMessage(message);  // (2)
  processMicroTaskQueue(); // (3)
}

因此,如果您有只执行阶段 (3) 的承诺,浏览器会不断卡在 (3),因此没有任何机会处理任何 , IOW:浏览器挂起!!macrotasks

希望这是有道理的,而且我使用了正确的术语等。

与 3.11 非常相似,一个写得不好的应用程序,从来没有给操作系统处理其事件循环的机会,实际上会挂起整个操作系统。 奇怪的是,这些事情怎么又来了。:)