SL-USER> (time (loop for i below (expt 10 8) count t))
Evaluation time: 19376ms
100000000
SL-USER> (time (loop for i below 1000000 count t))
Evaluation time: 272ms
1000000
SL-USER> (defun fib (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
#'FIB
SL-USER> (time (fib 32))
Evaluation time: 1601ms
2178309
These timings are in Firefox; Chromium is almost 2x faster. Also, it doesn't completely freeze the browser in the mean time (we have green threads).
Seems TAGBODY is compiled into a while(true) which sets an exception handler on each iteration. (and then, LOOP macroexpands into a TAGBODY). I don't think there's a better way to do it, BTW — JS is simply not a friendly compilation target. But `try` on each iteration is quite costly, that's most probably the bottleneck here.