The native API calls such as createElement are pretty expensive (in V8 it's like 10 function calls to finally reach the target C++ function) and you are making a lot more such calls when not using innerHTML.
Interesting, thanks. I had heard that calls from JS to C++ were cheap but calls from C++ to JS (such as if Array.prototype.map was implemented natively) were expensive.
Might depend on how you build the nodes. If you build all the nodes and then append it should be a lot faster. Maybe browsers have optimized for this use case better but I ran benchmarks on this a couple of years ago and createElement / appendChild was always a lot faster.
IE and Edge are much faster when appending nodes first (thus always appending empty nodes) but Chrome, Firefox, and Safari are similar speed regardless of the order. We do the former in IE and Edge only and the latter in all other browsers because it's more convenient (and makes more logical sense to me).