Я читал о стеке вызовов и очереди обратных вызовов. И я понимаю, что поведение, которое меня озадачивало, связано с тем, как Javascript обрабатывает различные стеки и очереди. Эта пьеса Джейка Арчибальда помогает прояснить ситуацию, хотя она немного поглощает все сразу.
Если я добавлю setTimeout с любым значением задержки, даже 0, foo ОБЫЧНО изменилось. При значениях, близких к нулю, оно немного меняется.
setTimeout(function(){
console.log('SetTimeout\n - Foo only changes if this goes AFTER the Promise\n foo:', foo)}
, 0);
Это скрипка, полученная из других, которая более четко показывает, что происходит. https://jsfiddle.net/TwoFistedJustice/arkqb0x8/71/