最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Save value of then in a variable outside of the Promise - Stack Overflow

programmeradmin0浏览0评论

I'm fairly new to the concept of Promises and I'm trying to understand how the scopes work. I'm basically trying to store the value from inside a then() into a variable outside of the Promise

Below is a simple function I've written in Nodejs (Express), using Sequelize to run the query on the DB.

exports.getTest = (req, res, next) => {
    var categories = [];
    var names = ['Category 1', 'Category 2', 'Category 3', 'Category 4'];
    for (var i = 0; i < names.length; i++) {
        model.Category.findOne({
            where: {
                name: names[i]
            },
            attributes: ['id']
        }).then(id => {
            categories.push(
            {
                category_id: id.id
            });
        });
    }
    res.json(categories);
}

I have other logic to be run after that, and I have a for loop around the Promise. So, I can't run my next logic inside the then, otherwise I'll have it running multiple times because of the for loop. I need to populate the array categories to use it in my next operation.

Currently, my response (res.json(categories)) is []

Any help would be appreciated.

PS: I know this is a mon topic, but as I mentioned, I'm fairly new to this and the other answers didn't fit my scenario and were further confusing me.

Thanks in advance!

I'm fairly new to the concept of Promises and I'm trying to understand how the scopes work. I'm basically trying to store the value from inside a then() into a variable outside of the Promise

Below is a simple function I've written in Nodejs (Express), using Sequelize to run the query on the DB.

exports.getTest = (req, res, next) => {
    var categories = [];
    var names = ['Category 1', 'Category 2', 'Category 3', 'Category 4'];
    for (var i = 0; i < names.length; i++) {
        model.Category.findOne({
            where: {
                name: names[i]
            },
            attributes: ['id']
        }).then(id => {
            categories.push(
            {
                category_id: id.id
            });
        });
    }
    res.json(categories);
}

I have other logic to be run after that, and I have a for loop around the Promise. So, I can't run my next logic inside the then, otherwise I'll have it running multiple times because of the for loop. I need to populate the array categories to use it in my next operation.

Currently, my response (res.json(categories)) is []

Any help would be appreciated.

PS: I know this is a mon topic, but as I mentioned, I'm fairly new to this and the other answers didn't fit my scenario and were further confusing me.

Thanks in advance!

Share Improve this question asked May 28, 2019 at 17:51 ashishsanjayraoashishsanjayrao 1013 silver badges15 bronze badges 1
  • have you tried using async/await? – Lordie Commented May 28, 2019 at 18:40
Add a ment  | 

3 Answers 3

Reset to default 3

In your case, categories will always return [] because you aren't waiting for all your promises to finish before returning your response. For loops do not wait for asynchronous actions to plete before continuing on to the next iteration. Therefore the loop ends, and a response is returned before any of them finish.

Instead of calling promises within a for loop, you should push them to an array, which you can then pass to Promise.all() function.

Here is what it should look like

exports.getTest = () => {
    var categories = [];
    var names = ['Category 1', 'Category 2', 'Category 3', 'Category 4'];
    var promiseArray = [];
    for (var i = 0; i < names.length; i++) {
        promiseArray.push(
          model.Category.findOne({
              where: {
                  name: names[i]
              },
              attributes: ['id']
          }).then(id => {
              categories.push(
              {
                  category_id: id.id
              });
          });
        )
    }

    return Promise.all(promiseArr)
}

getTest() now returns a promise, so it can be called like this

getTest()
  .then(data => {
    // data will be an array of promise responses
  }).catch(err => {
    console.log(err);
  })

You can try Promise.all()

https://developer.mozilla/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

The Promise.all() method returns a single Promise that resolves when all of the promises passed as an iterable have resolved or when the iterable contains no promises. It rejects with the reason of the first promise that rejects.

var getTest = (req, res, next) => {
    var categories = [];
    var promises = [];
    var names = ['Category 1', 'Category 2', 'Category 3', 'Category 4'];
    var resolveCount = 0;
    for (var i = 0; i < names.length; i++) {
        // Store the name in variable so that can be persistent and not
        // affected by the changing 'i' value
        const name = names[i]
        promises.push(new Promise((resolve, reject) => {
        
          // Your DB calls here. We shall use a simple timer to mimic the
          // effect
          setTimeout(() => {
            categories.push(name)
            resolveCount++;
            resolve();
          }, 1000)
        }));
    }
    
    
    Promise.all(promises).then(function() {
      console.log("This should run ONCE before AFTER promise resolved")
      console.log("resolveCount: " + resolveCount)
      console.log(categories);
      
      // Do your logic with the updated array
      // res.json(categories);
    });
    
    console.log("This will run immediately, before any promise resolve")
    console.log("resolveCount: " + resolveCount)
    console.log(categories)
}

getTest();

exports.getTest = (req, res, next) => {
    var categories = [];
    var names = ['Category 1', 'Category 2', 'Category 3', 'Category 4'];
    names.forEach(name => {
        Category.findOne({where: {name: name}}).then(category => {
            categories.push({category_id: category.id})
        })
    })
    res.json(categories);
}

So basically, model.findeOne() returns a promise with the object of the first category with each of the names. then() catches that promise, resolves it and you give it a callback function that get that object passed as a parameter.

It could look something like

Categories.findOne({where: {name: name}).then(function(category){
    // do something with that category
})

But the arrow function makes it a lot more readable as then(category => {//some code}).

发布评论

评论列表(0)

  1. 暂无评论