Una cosa interesante que me sorprende que nadie haya mencionado todavía es la diferencia en los tipos de compilación JIT, porque Flash todavía está compilado JIT y, en la mayoría de los navegadores modernos, también lo es JavaScript, sin embargo, Flash es un lenguaje fuertemente tipado, lo que significa hay todo un reino de optimizaciones que puede hacer (como emitir una llamada a un método directamente (algo que JavaScript no puede hacer)), que JavaScript no puede hacer porque está escrito dinámicamente. Puede reemplazar la definición completa de una función en JavaScript en cualquier momento que desee, y esa nueva definición es lo que debe llamarse. (todavía es posible que JavaScript haga una llamada indirecta que no sería mucho más costosa). El acceso de campo en un campo es en realidad un mejor ejemplo que la llamada al método, porque JavaScript ni siquiera puede hacer esto indirectamente,
Otra diferencia en el rendimiento es, como ya se mencionó, el GC. Sospecho (no lo he comprobado) que la mayoría de los navegadores usan un GC de recuento de referencia (porque toda la memoria que el GC asignó para una página se puede liberar cuando se deja la página, en realidad es uno de los mejores lugares para usar un GC de recuento de referencia ) o un GC de exploración conservador (como Boehm). Este último puede ser considerablemente más lento que el primero si no se implementa correctamente. (Boehm es un ejemplo de una implementación correcta) Flash, por otro lado, utiliza un GC preciso (mucho más fácil de hacer en un sistema fuertemente tipado). Debido a que Flash utiliza un GC preciso, no tiene la sobrecarga de tiempo de ejecución del recuento de referencias. (que no es enorme, pero sigue ahí) Un buen ejemplo de un GC preciso es el SGen de Mono, que también compacta los montones.
Luego viene el hecho de que JavaScript no fue diseñado con la animación en mente. (como también se mencionó) Hasta donde yo sé, ningún navegador emitirá instrucciones de estilo SSE para los bucles de animación, donde, como las funciones principales de representación en Flash, probablemente se han optimizado a mano para un rendimiento máximo. (en algunos lugares se escriben en ensamblado sin procesar)
En general, todo se reduce al hecho de que un lenguaje dinámico siempre será más lento que uno estáticamente tipado si tiene que compilarse de manera oportuna para no hacer que el usuario se queje de su lentitud.