Using a numbers table would be the best way to implement this.
You need to remember SQL Server is desiged to work with sets of rows. If you find yourself looping -always stop and think, could you approach the problem as a collection of rows?
The following implements a numbers table using a CTE (this would be a permanant table with rows from 1 up to whatever you need).
You can then select rows from the numbers table to match your requirements, in this case every 10th row using modulo, selecting the relevant substring portion. string_agg can then combine the rows back into a single string, automatically adding the comma separator.
The stuff function adds a comma to the beginning of the string like your own output produces, leave this off if that's not required.
declare @a varchar(max) = '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890';
with n as (select top(Len(@a)) n = Row_Number() over(order by (select null)) from master.sys.objects)
select Stuff(String_Agg(Substring(@a,n, 10),',') within group (order by n),1,0,',')
from n
where (n-1) % 10 = 0 and n <= Len(@a);
Performance comparison
Using a suitably long string to test with (320k characters), the looping method takes over 3 seconds.
The same result using the numbers table implementation above takes about 94 milliseconds, so approximately 34x faster.
See this demo fiddle with timings.