In a nutshell you will probably want to loop through an array of IdentifyTasks that each point to your repective services and properties.Once you have your array built up or something similar then you might want to look at Dojo.DeferredList of more current implementation of Dojo.PromiseAll. Note that the IdentifyTask.execute return a Dojo.Deferred object this is key in being able to use the methods mentioned above. The DeferredList allows you to make asynch calls to the server simultaneously and it will wait until the excute tasks have all finished. Below is some sample code that uses the DeferredList to execute select statements to the server simulateously. In your case, you would build your DeferredList (or better PromiseAll) of dojo.deferred array objects and them make the request to the server (identifyTask.execute()) and wait until the calls have finished (dl.then ..) . The within the deferredList.then is used to build up the results that are returned and then turn the values back in some kind of order that makes sense to you and your application. In my example below, I return a custom object "selectionLayers" that I need for processing (returnDeferred.resolve({ 'success': true, 'selectionLayers': selectionLayers }) )I am sure there are other ways to do this, but so far without having to create a custom service that does all this for me, I have found this to work for me when I am making multiple simultaneous requests to the server - if a deferred object is returned from the Javascript API. Good Luck!//sample code - not for production //should consider using Promise and PromiseAll function getSelectionLayerDeferred(featureLayerArray, selectQuery) { var returnDeferred = null; var selectionLayers = []; var defferredCallArray = []; require(["dojo/DeferredList", "dojo/Deferred"], function (DeferredList, Deferred) { returnDeferred = new Deferred(); dojo.forEach(featureLayerArray, function (flayer) { var defferredCall = flayer.selectFeatures(selectQuery, esri.layers.FeatureLayer.SELECTION_NEW); //cast the dojo.deferred to a promise so we can use the new //dojo/promise/all in lieu of dojo/DeferredList (deprecated at v 1.8) defferredCallArray.push(defferredCall); }); var dl = new DeferredList(defferredCallArray); dl.then(function (results) { // Executed when all deferred resolved if (results.length > 0) { dojo.forEach(results, function (result) { if (result[0] === true && result[1].length > 0) { selectionLayers.push({ 'featureLayer': result[1][0].getLayer(), 'features': result[1] }); } }); } returnDeferred.resolve({ 'success': true, 'selectionLayers': selectionLayers }); }, function (err) { returnDeferred.resolve({ 'success': false, 'selectionLayers': null, 'error': err }); }); }); return returnDeferred; } //here is some sample code of how I implement it //not for production //select related records var selQuery = new esri.tasks.Query(); selQuery.where = "GAZ_ID = " + updateGraphic.attributes["GAZ_ID"]; var deferred = getSelectionLayerDeferred([landformAllpointFeatureService], selectQuery); deferred.then(function (results) { if (results.success && results.selectionLayers) { //bind to data to add to grid //TODO: work in progress ... // buildDataStore(results.selectionLayers[0].features) setDisableToolbarControls(ToolbarType.Editor_Select, false); hideProcessingDialog(); refreshMap(); } else { setDisableToolbarControls(ToolbarType.Editor_Select, true); hideProcessingDialog(); } }, function (error) { // Do something on failure. hideProcessingDialog(); drawToolbar.deactivate(); //var err = results.error; alert("Error ...") });