Devolver inmediatamente una promesa resuelta usando AngularJS


Estoy tratando de conseguir mi cabeza alrededor de las promesas en JavaScript (en particular AngularJS).

Tengo una función en un servicio, llamémosla fooService, que comprueba si hemos cargado algunos datos. Si lo ha hecho, solo quiero que regrese, y si no lo hemos hecho, necesitamos cargar los datos y devolver una promesa:

this.update = function(data_loaded) {
    if (data_loaded) return;  // We've loaded the data, no need to update

    var promise = Restangular.all('someBase').customGet('foo/bar').then(function(data) {
        // Do something with the data here
    }

    return promise;
}

Tengo otra función que luego llama a la función update de fooService de la siguiente manera:

fooService.update(data_loaded).then(function() {
    // Do something here when update is finished
})

Mi problema aquí es que si no necesitamos cargar los datos en la función update, un promise no se devuelve, por lo que el .then() no se llama en mi otra función. ¿Cuál debería ser el enfoque aquí - básicamente quiero devolver una promesa resuelta inmediatamente desde la función update() si no necesitamos obtener datos de la llamada Restangular?

Author: Peter Mortensen, 2014-07-17

5 answers

La respuesta aceptada actual es excesivamente complicada, y abusa del patrón anti diferido. Aquí hay un enfoque más simple:

this.update = function(data_loaded) {
    if (data_loaded) return $q.when(data);  // We've loaded the data, no need to update

    return Restangular.all('someBase').customGet('foo/bar')
                             .then(function(data) {
        // Do something with the data here 
    });
};

O, aún más:

this._updatep = null;
this.update = function(data_loaded) { // cached
    this._updatep = this._updatep || Restangular.all('someBase') // process in
                                                .customGet('foo/bar'); //.then(..
    return this._updatep;
};
 26
Author: Benjamin Gruenbaum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:33

Como su promesa usa la misma sintaxis que la nativa de JavaScript, puede usar y devolver una promesa de JavaScript ya resuelta : Promise.resolver()

return(Promise.resolve("MyReturnValue"));
 39
Author: Elo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-09 08:56:00

Angularjs's $q el servicio le ayudará aquí. Es muy parecido a la biblioteca Q promise de Kris Kowal.

Cuando tenga un método asincrónico que pueda devolver una promesa o valor, use el $q. cuando método. Tomará lo que se le pase, ya sea una promesa o un valor y creará una promesa que se resolverá/rechazará en función de la promesa pasada, o se resolverá si se pasa un valor.

$q.when( fooService.update(data_loaded) ).then(function(data){
   //data will either be the data returned or the data
   //passed through from the promise
})

Y luego en su actualización función devolver los datos en lugar de simplemente devolver

if (data_loaded) return data_loaded;
 6
Author: Patrick Evans,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-17 03:48:10

Similar a La respuesta de Elo , puedes devolver una promesa ya resuelta usando la sintaxis async / await:

this.update = async (data_loaded) => {

    if (data_loaded) 
        return await null;  // Instead of null, you could also return something else
                            // like a string "Resolved" or an object { status: 200 }
    else 
        return await OtherPromise();
}
 0
Author: Zanon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-23 11:27:45

Podrías usar el $q.defer() así:

this.update = function (data_loaded) {
    var deferred = $q.defer();

    if (data_loaded) {
        deferred.resolve(null); // put something that your callback will know the data is loaded or just put your loaded data here.
    } else {
        Restangular.all('someBase').customGet('foo/bar').then(function(data) {
            // Do something here when update is finished
            deferred.resolve(data);
        }
    }

    return deferred.promise;
};

Espero que esto ayude.

 -2
Author: runTarm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-17 03:49:52