> if you are prepared to provide the value immediately then you don't have to return into the runloop
It might just my own mental model. But if I'm using a promise, it is a future value. So I don't understand why you would ever want to do that. Plus that's what Promise.resolve() is for. I'd expect them to act more like the now defunct setImmediate() function.
I concede that it may be more performant to do it this way as it results in less context switching, but I personally don't think performance should dictate a language's design of primitives.
To use Promise.resolve you have to know whether the value is ready or not before you enter the promise, but you should enter the promise and then check that status. There are very few situations where Promise.resolve should be used: it is essentially a weird performance optimization for constant values. A basic example is something like reading from a network buffer: you call read, and there might be data immediately or you might have to wait; and in JavaScript the way you read might involve a callback, so it isn't even like "check buffer and then use Promise.resolve as awkward special case" but instead "call read passing callback; if data is already there the callback is called immediately". This also comes up while implementing stuff like "a set of values that consumers can ask for a value from; if the set is empty they will have to wait until there is a value".
Regardless, I legitimately believe the mental model of it not switching back and forth is fundamentally more correct for the primitive. The goal should also be that the abstraction has the same behavior and ordering semantics as doing it by hand. When you do it by hand, you essentially must run the code there immediately as otherwise there is no way to even run that code at all. Why would you ever want that code to be delayed? It frankly sounds like you are modeling Promise as if it meant Thread or something... a Promise is just a tiny adapter whose purpose is to change a wrap some setup code for accessing the value of a later event together into a common interface. A promise isn't doing the work: it is adapting the API of random models of doing future work (one-off callback APIs, random evented interfaces, etc.) to its own. Having this allows us to hack in (due to the lack of good monad support in most programming languages) async/await in a non-horrific way. If you want to do future work your first step should be to come up with a model for how your future work will happen, and then you use Promises just to do this adaptation, not to like, spawn some computation that will take time and which should happen later.
It might just my own mental model. But if I'm using a promise, it is a future value. So I don't understand why you would ever want to do that. Plus that's what Promise.resolve() is for. I'd expect them to act more like the now defunct setImmediate() function.
I concede that it may be more performant to do it this way as it results in less context switching, but I personally don't think performance should dictate a language's design of primitives.