Promises stop working when adding a insertion quer

2019-09-13 15:09发布

问题:

Asking about promises with Q library for node, mido helped me with a problem with the execution of promises in this thread. Basically, the solution was (almost) this code.

    var form= [
        {'name':'FORM_NAME_1.1',
         'label2':'FORM_LABEL_1.2'
        },
        {'name':'FORM_NAME_2.1',
         'label2':'FORM_LABEL_2.2'
        }
    ];
    var params = ['params1','params2'];
    var meta   = ['meta1','meta2'];

    let process = (currentValue,index,arr) => {
        //let reqCopy = {id: Math.random()}
        let reqCopy = {};
        for(let attr in req)  // copy all the request attributes 
            //if(attr && attr!='id')
                reqCopy[attr] = req[attr]
        return Q.all([
            Form.insert(connection,req,form[index],reqCopy),
            Field.insert(connection,req,params[index],reqCopy),
            Meta.insert(connection,req,meta[index],reqCopy)
        ])
    }
    return Q.all(form.map(process))
    .catch((err) => console.log(err))
    .done(() => console.log('Done'));

But now I need to generate an id in the first promise (Form.insert) and pass it throw the others. It's easy to have the id of the inserted row using mySql library for Node. This is the promise form Form:

var Q = require('Q');

module.exports = {
    insert: (connection,req,dataToInsert,reqCopy) => {
        var deferred = Q.defer()
          , db       = 'DATABASE';

        console.log('Form.insert is executing with data: ' + JSON.stringify(dataToInsert));

    connection.query(`INSERT INTO ${db} SET ?`
        ,[dataToInsert]
        ,function(err, result) {
            if (err) deferred.reject(err);
            console.log('Result: ' + result.insertId);
            deferred.resolve(result.insertId); //Return id when data was inserted
        });

        return deferred.promise;
    }
}

But now, with the INSERT INTOquery, the first promise is executed at the end of the process, doing it fails again:

//Promises are executed in the right order set in the .all array:
Form.insert is executing with data: {"name":"crf_NAME_1.1","label2":"FORM_LABEL_1.2"}
Field.insert is executing with data: "params1"
Meta.insert is executing with data: "meta1"
Form.insert is executing with data: {"name":"FORM_NAME_2.1","label2":"FORM_LABEL_2.2"}
Field.insert is executing with data: "params2"
Meta.insert is executing with data: "meta2"

//But Form.insert should generate the id before passing to the next promise.
C:\node\api\models\Form.js:17
            console.log('Result: ' + result.insertId); //IT FAILS, SHOULD BE EXECUTED BEFORE

I don't understain why this occurs because Form.insert is defined as a promise and return values (resolve and reject) are set after inserting the data, so flow should wait for its resolution.

Thanks!

回答1:

if you want to pass the id from first promise to others, you can do something like:

...
let process = (currentValue,index,arr) => {
  return Form.insert(connection,req,form[index]).then(id => Q.all([
    Field.insert(connection,req,params[index],id),
    Meta.insert(connection,req,meta[index],id)
  ]))
}
...


回答2:

AFAIK, Q.all() is useful if the operations are independent of each other.

If there is a dependency, you can use regular Promise chaining:

return Form .insert(connection,req,form[index],reqCopy)
            .then((insertId) => {
              return Q.all([
                Field.insert(connection, req, insertId, params[index], reqCopy), 
                Meta .insert(connection, req, insertId, meta[index], reqCopy)
              ])
            })

This assumes that Field.insert() and Meta.insert() are still independent of each other; if not, you can use the same trick to pass data from the former to the latter. I added insertId as extra argument to the insert methods as an example.