https://docs.angularjs.org/api/ng/service/$q#-q-constructor utile dans ce genre de cas : besoin d'attendre le retour d'une fonction pour exécuter une action (cf. entete.ctl.js : après sauvegarde du formulaire libre, on veut revenir à l'écran liste mais il est nécessaire d'attendre la fin du saveForm avant d'exécuter le BaseFct.goto('route'))

fct.saveForm=function(refFormConfig,id,form,listBoxName, hideToast) {
  var deferred=$q.defer();
  FormulaireService.updateOrCreate(refFormConfig,id,fct.data.form).then(function(result) {
      if ((result.status === 200)||(result.status === 201)||(result=='NO_UPDATE')) {
          
          [...]
          
          deferred.resolve(result);
      } else {
          deferred.reject(result);
      }
  });
  return deferred.promise;
};

// utilisation de la promise
fct.saveForm(fct.data.entete.refFormulaireLibre_ControleDateR, $stateParams.id, fct.form, undefined, false).then(function(result) {
    if (result && (result.status===200 || result.status===201)) {
        BaseFct.goto('app.gestionsite.controledate'); // exécution de l'action qui doit suivre
    }
});

// autre exemple
fct.updatePec = function (refBenef, refActivite, refEntite) {
    if (refBenef) {
        var filterBenef = $filter('filter')(fct.data.pec, {idBeneficiaire: refBenef}, true);
        var deferred = $q.defer();
        if (angular.isArray(filterBenef) && (filterBenef.length > 0)) {
            for (var i = filterBenef[0].tasks.length - 1; i >= 0; i--) {
                filterBenef[0].tasks.splice(i, 1);
            }

            SuiviPecService.getSuiviByBenef(fct.data.gantt.dateDeb, fct.data.gantt.dateFin, refActivite, refEntite, refBenef).then(function (result) {
                if (result && (result.status === 200)) {
                    filterBenef = $filter('filter')(fct.data.pec, {idBeneficiaire: result.data.data.idBeneficiaire}, true);
                    filterBenef[0].tasks = filterBenef[0].tasks.concat(result.data.data.tasks);
                }
                deferred.resolve({data:{data:filterBenef[0].tasks}, status:result.status});
            });
        } else {
            deferred.resolve({data:{data:{}}, status:204});
        }
        return deferred.promise;
    }
};

fct.getTransmissionList = function (filters, sort, limit, offset, champs, meta, param) {
    var deferred = $q.defer();
    if (offset === 1) {
        if (angular.isArray(fct.listParams.transmissions.data.liste)) {
            ParamTransmissionService.consulter(filters, sort, limit, offset, champs, meta, fct.msId).then(function (result) {
                if (result && (result.status === 200)) {
                    deferred.resolve({status:result.status, data:{data:[result.data.data], meta:result.data.meta, 
                                      droits:result.data.droits, action:result.data.action, vueFront:result.data.vueFront, 
                                      actionEdition:result.data.actionEdition}});
                }
            });
        } else {
            deferred.resolve({status: 204});
        }
    } else {
        deferred.resolve({status: 204});
    }
    return deferred.promise;
};