Correct way to write loops for promise.

后端 未结 13 1719
猫巷女王i
猫巷女王i 2020-11-22 15:20

How to correctly construct a loop to make sure the following promise call and the chained logger.log(res) runs synchronously through iterat

相关标签:
13条回答
  • 2020-11-22 15:30

    Here's how I do it with the standard Promise object.

    // Given async function sayHi
    function sayHi() {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log('Hi');
          resolve();
        }, 3000);
      });
    }
    
    // And an array of async functions to loop through
    const asyncArray = [sayHi, sayHi, sayHi];
    
    // We create the start of a promise chain
    let chain = Promise.resolve();
    
    // And append each function in the array to the promise chain
    for (const func of asyncArray) {
      chain = chain.then(func);
    }
    
    // Output:
    // Hi
    // Hi (After 3 seconds)
    // Hi (After 3 more seconds)
    
    0 讨论(0)
  • 2020-11-22 15:31

    Using the standard promise object, and having the promise return the results.

    function promiseMap (data, f) {
      const reducer = (promise, x) =>
        promise.then(acc => f(x).then(y => acc.push(y) && acc))
      return data.reduce(reducer, Promise.resolve([]))
    }
    
    var emails = []
    
    function getUser(email) {
      return db.getUser(email)
    }
    
    promiseMap(emails, getUser).then(emails => {
      console.log(emails)
    })
    
    0 讨论(0)
  • 2020-11-22 15:34

    How about this one using BlueBird?

    function fetchUserDetails(arr) {
        return Promise.each(arr, function(email) {
            return db.getUser(email).done(function(res) {
                logger.log(res);
            });
        });
    }
    
    0 讨论(0)
  • 2020-11-22 15:35

    Bergi's suggested function is really nice:

    var promiseWhile = Promise.method(function(condition, action) {
          if (!condition()) return;
        return action().then(promiseWhile.bind(null, condition, action));
    });
    

    Still I want to make a tiny addition, which makes sense, when using promises:

    var promiseWhile = Promise.method(function(condition, action, lastValue) {
      if (!condition()) return lastValue;
      return action().then(promiseWhile.bind(null, condition, action));
    });
    

    This way the while loop can be embedded into a promise chain and resolves with lastValue (also if the action() is never run). See example:

    var count = 10;
    util.promiseWhile(
      function condition() {
        return count > 0;
      },
      function action() {
        return new Promise(function(resolve, reject) {
          count = count - 1;
          resolve(count)
        })
      },
      count)
    
    0 讨论(0)
  • 2020-11-22 15:37

    Given

    • asyncFn function
    • array of items

    Required

    • promise chaining .then()'s in series (in order)
    • native es6

    Solution

    let asyncFn = (item) => {
      return new Promise((resolve, reject) => {
        setTimeout( () => {console.log(item); resolve(true)}, 1000 )
      })
    }
    
    // asyncFn('a')
    // .then(()=>{return async('b')})
    // .then(()=>{return async('c')})
    // .then(()=>{return async('d')})
    
    let a = ['a','b','c','d']
    
    a.reduce((previous, current, index, array) => {
      return previous                                    // initiates the promise chain
      .then(()=>{return asyncFn(array[index])})      //adds .then() promise for each item
    }, Promise.resolve())
    
    0 讨论(0)
  • 2020-11-22 15:42

    I don't think it guarantees the order of calling logger.log(res);

    Actually, it does. That statement is executed before the resolve call.

    Any suggestions?

    Lots. The most important is your use of the create-promise-manually antipattern - just do only

    promiseWhile(…, function() {
        return db.getUser(email)
                 .then(function(res) { 
                     logger.log(res); 
                     count++;
                 });
    })…
    

    Second, that while function could be simplified a lot:

    var promiseWhile = Promise.method(function(condition, action) {
        if (!condition()) return;
        return action().then(promiseWhile.bind(null, condition, action));
    });
    

    Third, I would not use a while loop (with a closure variable) but a for loop:

    var promiseFor = Promise.method(function(condition, action, value) {
        if (!condition(value)) return value;
        return action(value).then(promiseFor.bind(null, condition, action));
    });
    
    promiseFor(function(count) {
        return count < 10;
    }, function(count) {
        return db.getUser(email)
                 .then(function(res) { 
                     logger.log(res); 
                     return ++count;
                 });
    }, 0).then(console.log.bind(console, 'all done'));
    
    0 讨论(0)
提交回复
热议问题