How to return value from a Promise

早过忘川 提交于 2019-12-24 04:50:23

问题


I have been struggling with Promises and would like to know how things work with Promises. In my project, I am using Bookshelfjs ORM for fetching the data from Postgres.

Here is the code that I am working on right now. I get an array of device ids in this request and each device is running in one of the two modes.

router.post('/devices', function (req, res, next) {
var currentData = [];
var deviceIds = req.body.devices;
loadash.forEach(deviceIds, function (device) {
    var deviceid = device.deviceid;
    Device.forge()
        .where({deviceid: deviceid})
        .fetch({columns: ['id', 'mode']})
        .then(function (fetchedDevice) {
            if(fetchedDevice.get('mode') === 1) {
                Model_1.forge()
                    .where({device_id: fetchedDevice.get('id')})
                    .orderBy('epoch_time', 'DESC')
                    .fetch()
                    .then(function (modelOne) {

                        //first push
                        currentData.push(modelOne.toJSON()); 

                        //array with first push data                
                        console.log(currentData)                                    
                    })
                    .catch(function (err) {
                        console.log(err);
                    });
            }
            else if(fetchedDevice.get('mode') === 2) {
                Model_2.forge()
                    .where({device_id: fetchedDevice.get('id')})
                    .orderBy('epoch_time', 'DESC')
                    .fetch()
                    .then(function (modelTwo) {

                        //second push
                        currentData.push(modelTwo.toJSON());

                        //array not empty here(shows data from both push)                
                        console.log(currentData);                                   
                    })
                    .catch(function (err) {
                        console.log(err);
                    });
            }
        })
        .catch(function (err) {
            console.log(err);
        });
   });
//This shows an empty array
console.log('Final: ' +currentData);                                                           
});

Now, I know this is happening because of async nature of Javascript. My question is

  1. how can I display final array after all push() have been executed? I tried doing this using Promise.all() method but did not have any success.

  2. is it possible to return modelOne or modelTwo out of every promise and then push to an array? How can I achieve this?


回答1:


Use .map() and Promise.all(), return a value from function passed to .then()

var currentData = loadash.map(deviceIds, function (device) {
    var deviceid = device.deviceid;
    return Device.forge()
        .where({deviceid: deviceid})
        .fetch({columns: ['id', 'mode']})
        .then(function (fetchedDevice) {
            if(fetchedDevice.get('mode') === 1) {
                // return value from `.then()`
                return Model_1.forge()
                    .where({device_id: fetchedDevice.get('id')})
                    .orderBy('epoch_time', 'DESC')
                    .fetch()
                    .then(function (modelOne) {
                        // return value from `.then()`
                        return modelOne.toJSON(); 

                    })
                    .catch(function (err) {
                        console.log(err);
                    });
            }
            else if(fetchedDevice.get('mode') === 2) {
                // return value from `.then()`
                return Model_2.forge()
                    .where({device_id: fetchedDevice.get('id')})
                    .orderBy('epoch_time', 'DESC')
                    .fetch()
                    .then(function (modelTwo) {
                        // return value from `.then()`
                        return modelTwo.toJSON();

                    })
            }
        })

   });

   var res = Promise.all(currentData);
   res
   .then(function(results) {console.log(results)})
   .catch(function (err) {
     console.log(err);
   });



回答2:


Try to avoid nesting then, and keep the promise chain flat. Furthermore, you can join the two model cases into one piece of code (DRY). Finally, use map instead of forEach so you return an array of promises, which you can then feed to Promise.all:

router.post('/devices', function (req, res, next) {
    var promises = loadash.map(req.body.devices, function (device) {
        return Device.forge()
            .where({deviceid: device.deviceid})
            .fetch({columns: ['id', 'mode']})
            .then(function (fetchedDevice) {
                var model = [Model_1, Model_2][fetchedDevice.get('mode')-1];
                if (model) {
                    return model.forge()
                        .where({device_id: fetchedDevice.get('id')})
                        .orderBy('epoch_time', 'DESC')
                        .fetch();
                }
            }).catch(function (err) {
                console.log(err);
            });
       });
    Promise.all(promises).then(function (currentData) {
        currentData = currentData.filter(model => model) // exclude undefined
            .map(model => model.toJSON());
        console.log('Final: ' +currentData); 
    });
}


来源:https://stackoverflow.com/questions/45122086/how-to-return-value-from-a-promise

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!