There are definitely patterns where a Promise API is more readable. You can implement a Promise API with or without separate threads, but if you execute it on a separate thread the number of library calls the Promise function can make isn't limited.
FWIW, I'd be careful about conflating issues such as how to handle I/O. Threads don't imply preemptive scheduling. Lua coroutines are implemented as threads, but that's the extent of things--there's no builtin scheduler or event loop nor features specifically directed toward implementing those things[1], just coroutine.resume and coroutine.yield. (yield can be called from any function at any depth as long as the call stack is on a coroutine thread, which in Lua is every stack except the main one.) And that's fine by me. The most fundamental issue from the perspective of the language design is about how to represent a thread of control that is consistent with the other structured programming constructs like function calls. A batteries-included event loop or a preemptive scheduler are nice to have, but notably they're much easier to implement (internally or third-party) and use if you have a thread construct.
FWIW, I'd be careful about conflating issues such as how to handle I/O. Threads don't imply preemptive scheduling. Lua coroutines are implemented as threads, but that's the extent of things--there's no builtin scheduler or event loop nor features specifically directed toward implementing those things[1], just coroutine.resume and coroutine.yield. (yield can be called from any function at any depth as long as the call stack is on a coroutine thread, which in Lua is every stack except the main one.) And that's fine by me. The most fundamental issue from the perspective of the language design is about how to represent a thread of control that is consistent with the other structured programming constructs like function calls. A batteries-included event loop or a preemptive scheduler are nice to have, but notably they're much easier to implement (internally or third-party) and use if you have a thread construct.
[1] Debugging hooks notwithstanding.