Hmm. Keep in mind that the async flag is long since deprecated; I hadn't realized that it was even available any more. But taking that as read, here's roughly what's involved. (Obviously untested; adapt as needed to the reality of your situation.)
My impression from your description is that the result is a JSON string, which is actually encoding an array. That being the case, the first step is to parse that:
val rawArray:js.Dynamic = JSON.parse(res)
That parses the JSON string, and gives you a js.Dynamic, which is the "raw" form of a JS object. At this point, Scala.js knows nothing about its structure.
Next, you should describe to Scala.js what the structure of each element of your array looks like:
@js.native
trait MyStruct extends js.Object {
val name:String = js.native
}
This is how you instruct Scala.js about a JavaScript type. You're telling it that this type has a property named "name", which is a String. You can add the other fields of the type or not, as you prefer -- since it sounds like you only care about name, you don't need to list the rest.
Then, you tell Scala.js what your rawArray really is:
val myArray = rawArray.asInstanceOf[js.Array[MyStruct]]
asInstanceOf doesn't change anything -- it is just declaring to Scala.js, "I know that this js.Dynamic is actually an Array of MyStruct". So now you have myArray, which is a js.Array[MyStruct], and you can use map as normal:
val myNames = myArray.map(_.name)
This sort of stuff is pretty normal when you're operating at the boundary of Scala.js and raw JavaScript. Since the JS level is completely untyped, and the SJS level is strongly typed, you have to "teach" SJS what the actual types coming out of the JS level are. Then you can just assume those types in the rest of the SJS code...