【问题标题】:How to return value from a Promise如何从 Promise 中返回值
【发布时间】:2017-12-20 16:24:06
【问题描述】:

我一直在为 Promises 苦苦挣扎,想知道 Promises 是如何工作的。 在我的项目中,我使用 Bookshelfjs ORM 从 Postgres 中获取数据。

这是我现在正在处理的代码。我在此请求中获得了一组设备 ID,并且每个设备都以两种模式之一运行。

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);                                                           
});

现在,我知道这是由于 Javascript 的异步特性而发生的。我的问题是

  1. 在所有push() 都已执行后,如何显示最终数组?我尝试使用Promise.all() 方法执行此操作,但没有成功。

  2. 是否可以从每个 promise 中返回 modelOnemodelTwo 然后推送到数组?我怎样才能做到这一点?

【问题讨论】:

  • 1.您将需要类似 Promise.all(arrayOfThings.map(() => (//return a promise))).then((results//结果数组) => (_.forEach(...))) ; 2. 你可以通过resolve从promise中返回一个对象。您可以通过 resolve({modelOne: ... , modelTwo: ...}) 返回,然后通过 then((result) => { use it }); 在 then 函数中使用它们
  • @TyanHauChiau 正如我所说,我尝试了Promise.all(),但我只从Device.forge() 承诺中获得了价值。也许我做错了,或者把它放在了错误的位置。您能否解释一下如何使用Promise.all() 正确实现这一目标?
  • 你的代码看起来像这样吗:假设你为一个名为 deviceFunc() 的设备包装了所有异步函数 { return new Promise((resolve, reject) => (if (model1) resolve(model1 ) 否则解决(model1))) }。并且您想获得所有设备的数组。你做 Promise.all(devices.map((device, index) => (deciveFunc(device))))

标签: javascript postgresql express promise bookshelf.js


【解决方案1】:

使用.map()Promise.all()return 传递给.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);
   });

【讨论】:

  • 太棒了!这按预期工作。所以只要知道我理解正确 - return modelOne.toJSON() 将值返回到外部 then() 并且这个外部 then() 函数将该值返回到 map 函数,对吗?
  • 是的。 .toJSON() 是否返回 Promise 或不是 Promise 的值?
  • 我认为它返回一个带有模型属性值的 Promise。
  • .then() 返回的Promise 应该导致Promise 在链式.then() Promise.resolve(1) .then(res => Promise.resolve(2).then(data => data)) .then(res => console.log(res)) // 2 处的值
  • 抱歉,根据 Bookshelf 文档toJSON() 将序列化模型作为普通对象返回
【解决方案2】:

尽量避免嵌套then,并保持承诺链平坦。此外,您可以将两个模型案例合并为一段代码(DRY)。最后,使用map 而不是forEach,这样您就可以返回一组promise,然后您可以将其提供给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); 
    });
}

【讨论】:

  • 是否应该将.catch() 链接到Promise.all()
  • 它可能在那儿或在个别承诺上。在第二种情况下,您仍然会得到基于其他承诺的结果。取决于 OP 的期望。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-28
  • 1970-01-01
  • 1970-01-01
  • 2013-10-26
  • 2021-08-25
  • 2021-08-08
相关资源
最近更新 更多