Skip to content

Promises executor dominates over timeouts #4129

Closed
@djspiewak

Description

@djspiewak

First, some table-setting:

var canceled = false;

const loop = () => {
  if (!canceled) {
    console.log("looping");
    new Promise((resolve, reject) => loop());
  }
};

setTimeout(() => { console.log("canceling"); canceled = true; }, 5);
loop();

This does what you would expect: it loops for a while and then cancels.

So does the following:

import scala.concurrent.ExecutionContext
import scala.concurrent.duration._
import scala.scalajs.concurrent.QueueExecutionContext
import scala.scalajs.js.timers

object Test {
  def main(args: Array[String]): Unit = {
    var cancel = false
    val exec: ExecutionContext = QueueExecutionContext.timeouts()
    def loop(): Unit = {
      if (!cancel) {
        println("looping")
        exec.execute(() => loop())
      }
    }

    timers.setTimeout(5.millis) { println("canceling"); cancel = true }
    loop()
  }
}

Again, loops for a little while and then cancels.

This, however, loops forever:

import scala.concurrent.ExecutionContext
import scala.concurrent.duration._
import scala.scalajs.concurrent.QueueExecutionContext
import scala.scalajs.js.timers

object Test {
  def main(args: Array[String]): Unit = {
    var cancel = false
    val exec: ExecutionContext = QueueExecutionContext.promises()        // <---- this is the only difference!
    def loop(): Unit = {
      if (!cancel) {
        println("looping")
        exec.execute(() => loop())
      }
    }

    timers.setTimeout(5.millis) { println("canceling"); cancel = true }
    loop()
  }
}

It appears that if any outstanding work is available on the promises queue, it will dominate over the timeouts queue. My guess without looking at the code is that this is a consequence of a well-intentioned optimization within ScalaJS itself which fails to yield, since it definitely doesn't reproduce within Node.

Metadata

Metadata

Assignees

Labels

enhancementFeature request (that does not concern language semantics, see "language")

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions