Estoy recorriendo un conjunto y, en cada ciclo, agrego un conjunto de promesas que luego se pasa a $q.all. Cada cadena incluye un diálogo confirm() y un modal. La secuencia de eventos para el usuario debe ser confirm () - modal - confirm () - modal. En cambio, obtengo confirmar () - confirmar () - modal - modal. Además, me gustaría que se ejecute una función refreshSelection() después de que se cierre el último modal, pero actualmente se activa tan pronto como se cierra el último diálogo confirm().

    var promiseArr = [];
    var selection = []; // [obj1, obj1, obj3...]

    for (var i = 0; i < selection.length; i++) {
        promiseArr.push(getData(i));
    }

    $q.all(promiseArr)
        .then(refreshSelection);

    function getData(i) {
        var opts = {}; // selection[i].id is param

        return $http(opts)
            .then(onGetSuccess(i));
    }

    function onGetSuccess(i) {
        return function(result) {
            var shouldOpenModal = confirm(selection[i].text);

            if (shouldOpenModal == true) {
                openModal();
            }
        }
    }

    function openModal() {
        var copyPunchesModal = $uibModal.open({
            // modal template options
            }
        });

        copyPunchesModal.result.then(otherFunc, function () {
            console.log("Modal closed");
        });
    }

    function refreshSelection() {
        selection = [];
    }

También he intentado lo siguiente en vano.

    //...
    function getData(i) {
        var opts = {}; // selection[i].id is param

        return $http(opts)
            .then(onGetSuccess(i))
            .then(openConfirm)
            .then(openModal);
    }

La ayuda es muy apreciada.

2
devthorne 11 may. 2016 a las 03:05

3 respuestas

La mejor respuesta

Q.all no especifica el orden en que se resolverán las promesas. Si desea que las promesas se completen en el orden de la matriz, debe encadenar las promesas para que la promesa actual se ejecute dentro del .then () de la promesa anterior.

Puedes hacerlo limpiamente con reduce.

Tengo una respuesta aquí para las promesas de ES6, aquí está adaptada a Q:

deferred = $q.defer();
deferred.resolve();
return selection.reduce(
    (accumulator, current) => accumulator.then(()=>getData(current)), 
    deferred.promise
);

Tenga en cuenta que también necesitará modificar su función getData para operar en el objeto en sí (por lo tanto, currentSelection.text en lugar de selection[i].text, por ejemplo)

2
Community 23 may. 2017 a las 12:31

Desea utilizar una función $ .when, que toma como argumento una serie de promesas y ejecuta una función cuando todas se completan. Alternativamente, puede conectarlos todos juntos si está de acuerdo con que se completen en orden secuencial.

https://api.jquery.com/jquery.when/

0
user3538411 11 may. 2016 a las 00:13

Quería hacer algo similar para evitar desbordar un dispositivo que mi programa estaba controlando, básicamente necesitaba esperar a que se completara la transacción asíncrona antes de comenzar la siguiente. Usé promesas para hacer cumplir tanto el orden de ejecución como para bloquear hasta que se completara cada elemento.

// the async thing we want to do, wrapped in a promise
//
function sendMessage = (message) {
    var promise = new Promise (resolve, reject) {
        // send message via an async function that provides success & fail callbacks, e.g. AJAX
        // replace 'asyncFunction', it's just a placeholder in this example
        asyncFunction (message, 
            function (response) {   // success callback
                if (/*response is to my liking*/) {
                    resolve ();
                } else {
                    reject (new Error (/*why I didn't like the response*/));
                }
            },
            function (error) {  // failure callback
                reject (error);
            }
    };
    return promise;
}

// the array we want to process in order
var myMessages = ['hello', 'world', 'how', 'are', 'you', 'today?'];

// iterator, and recursive function to loop thru array
var idx = 0;
function next () {
    if (idx < myMessages.length) {
        sendMessage (myMessages[idx++]).then (
            next,   // maps to the 'resolve' call in sendMessage
            function (err) {    // maps to the 'reject' calls in sendMessage
                throw err;  // clearly, there's an option to be smarter than this
            }
        )
    }
}

// start the recursion
next ();
0
VorpalSword 10 jun. 2016 a las 20:56