admin管理员组

文章数量:1421054

I'm very new to Javascript and suspect I have a basic mistake. I want to run a loop in order, but I'm using promises, and they're stuck in a "pending" state.

function print(i){
    return new Promise(function(resolve,reject){
      console.log(i);
      resolve();
    });
}

counter = 0;
var sequence = Promise.resolve();

// The real while loop is much more plicated than this
while (counter < 10) {
    sequence = sequence.then(function() {
      print(counter);
    }).then(function() {
      counter += 1;
    });
}

My problem is very similar to this question, except that I still get stuck in the pending state even though I make the call to resolve(). What am I doing wrong?

I'm very new to Javascript and suspect I have a basic mistake. I want to run a loop in order, but I'm using promises, and they're stuck in a "pending" state.

function print(i){
    return new Promise(function(resolve,reject){
      console.log(i);
      resolve();
    });
}

counter = 0;
var sequence = Promise.resolve();

// The real while loop is much more plicated than this
while (counter < 10) {
    sequence = sequence.then(function() {
      print(counter);
    }).then(function() {
      counter += 1;
    });
}

My problem is very similar to this question, except that I still get stuck in the pending state even though I make the call to resolve(). What am I doing wrong?

Share Improve this question asked Aug 19, 2018 at 22:07 user554481user554481 2,0754 gold badges31 silver badges53 bronze badges 2
  • 3 This pattern doesn't work because the while run synchronously and the current event loop never finishes because the while loop is running. then() won't fire until the next event loop. – Mark Commented Aug 19, 2018 at 22:17
  • 1 Another way to think of it: if you're going to return a Promise, then you need to "resolve()" when the asynchronous even occurs, when you're USING the promise. NOT when you declare the promise (as in your example). ALSO: Iou do not NEED to use await with Promise. Two good reasons to avoid await: 1) "await()" isn't EMCA6 pliant (promises are), 2) many browsers (including IE11) don't support it. – paulsm4 Commented Aug 26, 2018 at 22:16
Add a ment  | 

2 Answers 2

Reset to default 4

You have two issues. The simpler one is that you aren't returning the result of print, and therefore you are never waiting for the promise to resolve before continuing.

The bigger issue is that your while loop is trying to bine a synchronous loop with promises. Basically, your while loop pseudocode looks like this:

while counter < 10:
  spawn an async task
end

Since counter is only incremented in your async task, the while loop will never end. More importantly, since your while loop never stops, your async tasks never kick off, as javascript is single threaded.

You can solve this with using await as follows:

function print(i) {
  return new Promise(function(resolve, reject) {
    console.log(i);
    resolve();
  });
}

async function runLoop() {
  let counter = 0;
  while (counter < 10) {
    const result = await print(counter);
    counter += 1;
  }
}

runLoop().then(() => {
  console.log('done');
});

If you cant use async/await you can use array.reduce to sequentially resolve the promises. In that case I let the print function return a function that we can later invoke.

function print(i) {
  return function() {
      return new Promise(function(resolve,reject){
        console.log(i);
        resolve();
      });
  }
}

We then initialize our empty promiseArray, and our counter

const promiseArray = [];
let counter = 0;

We can now add 10 print functions to our array.

while (counter < 10) {
    promiseArray.push(print(counter));
    counter++;
}

Not that the print function now returns a another function. We haven't invoked that function and we haven't tried to resolve our promises. If the print function would've returned a promise (and not a function) the promise would get resolved, and it wouldn't be sequantially resolved. Since we can't guarantee that print(1) finishes before print(2). It would just start some print calls and resolve in whatever order.

To sequantially resolve the promises we use array reduce that starts with an empty promise, resolves it and then calls the next promise function.

promiseArray.reduce((init,curr) => {
    return init.then(curr);
},Promise.resolve())

A full code snippet would look like this:

function print(i) {
  return function() {
      return new Promise(function(resolve,reject){
        console.log(i);
        resolve();
      });
  }
}

const promiseArray = [];
let counter = 0;
// The real while loop is much more plicated than this
while (counter < 10) {
    promiseArray.push(print(counter));
    counter++;
}

promiseArray.reduce((init,curr) => {
	return init.then(curr);
},Promise.resolve())

本文标签: Javascript promise stuck in pending stateStack Overflow