1

I'm trying to generalize a script that encrypts forms using OpenPGP libraries. I got some troubles with the client-side code (Javascript) :

var working = formID.elements[0];
var counter = 0;

while (working) {
    encrypt(working.value).then(function(encrypted_msg) {
        console.log("processing");
        working.value = encrypted_msg;
    });
    console.log("assuming processed");
    var counter = counter + 1;
    var working = formID.elements[counter];
}

The following code should take each form element and encrypt its value. However, the while loop doesn't wait for the asynchronous encrypt() function to be resolved.

I think i need to use promises in this case, but i have no idea how and the few tutorials didn't work in a while loop.

Help ?

Gaby
  • 97
  • 1
  • 2
  • 11

2 Answers2

2

Probably can be used list of jQuery deferreds, something like this:

var deferreds = [];

$.each(formID.elements, function(key, working){

    var deferred = $.Deferred();
    deferreds.push(deferred);

    encrypt(working.value).then(function(encrypted_msg) {
        console.log("processing");
        working.value = encrypted_msg;
        deferred.resolve();
    });

});

$.when.apply( $, deferreds ).done(function(){
    console.log( 'after all encryptions!' );
});

Of course, can be used native Promise object instead $.Deferred, however I think $.Deferred is more cross-browser way.

UPD2:

Improved answer based on native Promise and Promise.resolve() (thanks to @Bergi). For the case when encrypt() returns correct promise, method Promise.resolve() can be skipped.

var promises = [];

$.each(formID.elements, function(key, working){

    var promise = Promise.resolve(encrypt(working.value))
        .then(function(encrypted_msg) {
            console.log("processing");
            working.value = encrypted_msg;
        });

    promises.push(promise);

});

Promise.all(promises).then(function(){
    console.log( 'after all encryptions!' );
});
IStranger
  • 1,868
  • 15
  • 23
  • 1
    In theory, yes, but [avoid the deferred antipattern](http://stackoverflow.com/q/23803743/1048572)! – Bergi Sep 28 '16 at 17:32
  • @Bergi Yes, it is bad practice to create excess deferreds/promices. But I don't know what object returns `encrypt` method and how it will work with `$.when()` or `Promise.all()`. The fact that this object contains `.then` method, not much to say about him. I updated answer without antipattern. – IStranger Sep 28 '16 at 18:01
  • @IStranger If you don't know what it returns, you can always use `Promise.resolve(encrypt(…))` (or `$.when(encrypt(…))` in jQuery), that's what they are for. – Bergi Sep 28 '16 at 18:36
  • 2
    @Bergi Thanks, it is awesome method). I like similar methods that allows to unify type without `if` statements and additional abstract layers. I improved answer using it. – IStranger Sep 29 '16 at 06:10
1
var iterator = [];
for (var counter = 0; counter < formID.elements.length; counter++) {
    var working = formID.elements[counter];
    iterator.push(encrypt(working.value));
}

Promise.all(iterator)
.then(fumction(data){
    //Here you have all data
})

You can synchronize your operation like this way. By collecting all asynchronus value references and point to them when they have data.

In case your data is dependent.

function myfunction(previousValue){
    if(breaking Condition){
        return Promise.resolve();
    }
    return encrypt(working.value).then(function(encrypted_msg) {
        working.value = encrypted_msg;
        return myfunction(working);
    });
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375