console.log("execution order");
console.log("1");                                     
dojo.forEach(loadedServices, function(service) {
    mapService = map.getLayer(service);
    layerids.length = 0;                                                                    //reset layerids array
    
    if (mapService.visibleLayers.length > 0) {                                      //does service have visible layers?
        url = mapService.url;                                                             //get url of service
        identifyTask = new esri.tasks.IdentifyTask(url);                          //ceate new identify task 
        identifyParams.layerIds = mapService.visibleLayers;                    //other params set in init function
            
        //var idDeferred = identifyTask.execute(identifyParams);              //tried using return deferred object
        //idDeferred.then(function(idResults) {                                     //results the same, not right approach
        identifyTask.execute(identifyParams,
            function(idResults) {
                
                //populate object for service and visible layers
                if (idResults.length>0) {
                    console.log("2");                                                      //execution order, understand it is async
                    
                    cp = new dijit.layout.ContentPane ({                          //create a new tab for each service results
                    title: service,
                    style: "height:100px; width: 300px; color:#000000 background-image:none;background-color:transparent;"
                    });
                    addToCP(idResults);                                               //process results into contentPane
                    
                    tc.addChild(cp);                                                    //add contentPane to tab container 
                    console.log(tc.hasChildren());                                  //is true....
                }
            },
            
            function(err) {
                console.log("doIdentify: (" + err.name + ") " + err.message);
            });
    }
});
console.log("3");
console.log(tc);
if (tc.hasChildren()) {                                                    //is always false due to 
tc.startup();
    map.infoWindow.setContent(tc.domNode);
    map.infoWindow.show(evt.screenPoint, map.getInfoWindowAnchor(evt.screenPoint));
} else {
    alert('No results found, please check layer visibility and try again.');
}//thanks David for help on handling tracking of callback completion
var callback_counter=0;
var expected_callback_counter=0;
dojo.forEach(loadedServices, function(service) {
    mapService = map.getLayer(service);
    if (mapService.visibleLayers.length > 0) {              
        expected_callback_counter++;                        //every visible layer should produce a callback, even if no results
    }
});
//for each loaded non-base layer service
dojo.forEach(loadedServices, function(service) {
    mapService = map.getLayer(service);                     //get service object
    layerids.length = 0;
    
    if (mapService.visibleLayers.length > 0) {              //does service have visible layers?
        showLoading();
        url = mapService.url;                               //get url of service
        identifyTask = new esri.tasks.IdentifyTask(url);    //ceate new identify task
        identifyParams.layerIds = mapService.visibleLayers; //set layers to identify
        identifyTask.execute(identifyParams,
            function(idResults) {                           //callback function - fires for each visible layer
                if (idResults.length>0) {                   //create tab for service if results returned
                    cp = new dijit.layout.ContentPane ({
                    title: service,
                    style: "height:150px; width: 400px; color:#000000 background-image:none;background-color:transparent;"
                    });
                    
                    //dojo.forEach (allResults, function(result) {allResults.push(result)});  //may use different display, need allResults at once
                    addToMap(idResults);                    //process results into containter content
                    
                    tc.addChild(cp);
                }
                
                callback_counter++;                         //a callback has fired - count them
                
                if (callback_counter == expected_callback_counter) {
                    if (tc.hasChildren()) {                 //may have no results across all services
                        tc.startup();
                        map.infoWindow.setContent(tc.domNode);
                        hideLoading();
                        map.infoWindow.show(evt.screenPoint, map.getInfoWindowAnchor(evt.screenPoint));
                        //addToMap2(allResults);
                    }
                    else {
                        alert('No results found!');
                    }
                }
            },
            
            function(err) {                                 //error callback
                console.log("doIdentify: (" + err.name + ") " + err.message);
            }
					
				
			
			
				
			
			
				
			
			
			
			
			
			
		Even though this is an old post, I just want to say how much it helped me today. Absolutely outstanding! I did have to massage this code lightly to get it to work. I added some logic to only identify visible map service layers. Also, rather than creating a custom content box for the response, I was able to use map.infoWindow setFeatures and show methods to use the default map info window. Additionally, I tied it all to a map click event. Of course, I will need to take additional time to format info Templates for each layer. Here is my code:
 map.on("click", function (event) {
    //Identify tasks
    let identifyParams = new IdentifyParameters();
    identifyParams.tolerance = 3;
    identifyParams.returnGeometry = true;
    identifyParams.width = map.width;
    identifyParams.height = map.height;
    identifyParams.mapExtent = map.extent;
    identifyParams.geometry = event.mapPoint;
    let callback_counter = 0;
    let expected_callback_counter = 0;
    dojo.forEach(loadedMapServices, function (service) {
      let mapService = map.getLayer(service);
      if (mapService.visibleLayers.length > 0) {
        expected_callback_counter++; //every visible layer should produce a callback, even if no results  
      }
    });
    //for each loaded non-base layer service  
    let deferred = [];
    dojo.forEach(loadedMapServices, function (service) {
      let mapService = map.getLayer(service); //get service object  
      if (mapService.visible) {
        if (mapService.visibleLayers.length > 0) { //does service have visible layers?  
          // showLoading();  
          let url = mapService.url; //get url of service  
          let identifyTask = new IdentifyTask(url); //ceate new identify task  
          identifyParams.layerIds = mapService.visibleLayers; //set layers to identify  
          let deferred_idTask = identifyTask
            .execute(identifyParams)
            .addCallback(function (response) {
              // response is an array of identify result objects
              // Let's return an array of features.
              return arrayUtils.map(response, function (result) {
                let feature = result.feature;
                let desc = result.layerName;
                console.log(feature);
                let Template = new InfoTemplate(desc, "${*}");
                feature.setInfoTemplate(Template);
                return feature;
              });
            });
          deferred.push(deferred_idTask);
        }
      }
    });
    map.infoWindow.setFeatures(deferred);
    map.infoWindow.show(event.mapPoint);
  });
  
});