Как зациклить функцию внутри себя без Promise?
Вас по сути попросили свои Promise написать. Зациклить там не получится, т.к. чейнинг тогда не будет работать (как у вас например).
Вот простенький вариант того, как будет работать. Т.е. собираем все функции сразу, сохраняем все хэндлеры в массиве handlers, и затем уже вызываем асинхронное ожидание чего-то.var def = {
      handlers: [],
      when : function (func) {
        console.log ('start async');
        func.call(def, def.done);
        waiter();
        function waiter() {
          setTimeout (function () {
            if (def.result) {
              def.resolve(def.result);
            }
            else {
              waiter();
            }
          }, 500);
        }
        

          return def;
      },
      
      resolve: function(result) {
        console.log('start resolving');
        var _result = result;
        def.handlers.forEach(function(handler) {
          _result = handler(result);
        });
        def.result = _result;
      },
      then : function (func) {
        def.handlers.push(func);
        return def;
      },
      
      done : function (result) {
        def.result = result;
      }
      
    };
Я правильно понимаю, что нужен yield? Если да, то бывают полифиллы, ну или может какой-нить Babel в ES5 сумеет перегнать.