“Iterating” throw promises does not let to generat

2019-09-09 22:52发布

问题:

Reading some amazing tutorials about promises, I've discovered that, if I need to interate throw some promises, I can't use forEach or some other "traditional" iteration mechanisms, I have to use Q library for node, I've to "iterate" using Q.all.

I've written a simple example in Nodejs Express in order to be sure I've understood promises:

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'];

app.get('/', (req,res) => {
        return Q.all([
            form.map((currentValue,index,arr) => {
                req.id = Math.random();   //Random ID to be used in the next promises
                console.log(currentValue);
                return Form.insert(currentValue,req);
            }),
            params.map((currentValue,index,arr) => {
                console.log(req.id);
                return Field.insert(currentValue,req.id);
            }),
            meta.map((currentValue,index,arr) => {
                console.log(req.id);
                return Meta.insert(currentValue,req.id);
            })
        ])
    .catch((err) => next(err))
    .done(() => console.log('It\'s done'));
});

Form.insert code simply is a promise with a console.log call, the same for Field.insert and Meta.insert

var Form = {
    insert: (param1,req) => {
        var deferred = Q.defer();
        console.log('Goes throw Form');
        deferred.resolve();
        return deferred.promise;
    }
}

The problem is that seems to iterate right but the dynamicly generated id does not change along the promises, this is the console output:

Listening at port 3000...
{ name: 'FORM_NAME_1.1', label2: 'FORM_LABEL_1.2' }
Goes throw Form
{ name: 'FORM_NAME_2.1', label2: 'FORM_LABEL_2.2' }
Goes throw Form
0.3757301066790548
Goes throw Field
0.3757301066790548
Goes throw Field
0.3757301066790548
Goes throw Meta
0.3757301066790548
Goes throw Meta
It's done

Any ideas about what is going wrong? Thanks!!

回答1:

the reason it is not working is because in first for loop, the req.id is set multiple times before other promises are started and and all of them end up using the last randomly generated value, change your code to:

app.get('/', (req,res) => {

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

you would notice that I am copying all the attributes of req to clone reqCopy for I am not sure what attributes of req are required by the subsequent methods, but at the same time, single req.id would not work thanks to the async nature of code