重复一个Promise,直到它没有被拒绝或超时为止

Repeat a Promise until it's not rejected or reach a timeout

本文关键字:拒绝 超时 Promise 一个      更新时间:2023-09-26

我仍然是一个承诺新手,我正在努力找出如何让我的承诺重复自己。

有一个ES6承诺,如果没有设置某个全局标志,它会拒绝。我需要它每500毫秒重试一次,直到:

  • 承诺返回解析,
  • 或达到最大尝试数(假设为10)。

因为promise是异步的,我真的不想使用setInterval()检查,因为我不认为这将与异步代码正确工作。我需要检查在承诺被成功解决(或超时)后立即终止。

我使用ES6 + React + ES6 Promises(所以没有Q或bluebird特定的答案,请!)

http://jsfiddle.net/2k2kz9r9/8/

// CLASS
class Test extends React.Component {
    constructor() {
      this.state = {
        status: 'setting up..',
      }
    }
    componentDidMount() {
      // TODO: how do I get this to loop with a timeout?
      this.createSlot()
        .then((slot) => {
          this.setState({
            status: slot
          });
        })
        .catch((e) => {
          this.setState({
            status: e.message
          });
        })
    }
    createSlot() {
      return new Promise((resolve, reject) => {
        if (!this.checkIsReady()) {
          reject(new Error('Global isnt ready yet'));
        }
        // more stuff here but going to resolve a string for simplicity sake
        resolve('successful!');
      });
    }
    checkIsReady() {
      return window.globalThing && window.globalThing === true;
    }
    render() {
        return ( <div>{this.state.status}</div> );
    }
}


    // RENDER OUT
    React.render(< Test/> , document.getElementById('container'));

EDIT:基于当前反馈的函数:

  createSlot(tries) {
    const _this = this;
    return new Promise(function cb(resolve, reject) {
      console.log(`${tries} remaining`);
      if (--tries > 0) {
        setTimeout(() => {
          cb(resolve, reject);
        }, 500);
      } else {
        const { divId, adUnitPath } = _this;
        const { sizes } = _this.props;
        // if it's not, reject
        if (!_this.isPubadsReady()) {
          reject(new Error('pubads not ready'));
        }
        // if it's there resolve
        window.googletag.cmd.push(() => {
          const slot = window.googletag
            .defineSlot(adUnitPath, sizes, divId)
            .addService(window.googletag.pubads());
          resolve(slot);
        });
      }
    });
  }

正如Mike McCaughan所提到的,您可以使用setTimeout在尝试之间创建延迟。一旦你的承诺成功了,或者你没有尝试过,就下定决心或拒绝它。

function createPromise(tries, willFail) {
  return new Promise(function cb(resolve, reject) {
    console.log(tries + ' remaining');
    if (--tries > 0) {
      setTimeout(function() {
        cb(resolve, reject);
      }, 500);
    } else {
      if (willFail) {
        reject('Failure');
      } else {
        resolve('Success');
      }
    }
  });
}
// This one will fail after 3 attempts
createPromise(3, true)
  .then(msg => console.log('should not run'))
  .catch(msg => {
    console.log(msg);
    
    // This one will succeed after 5 attempts
    return createPromise(5, false);
  })
  .then(msg => console.log(msg))
  .catch(msg => console.log('should not run'));

您可以尝试链接调用,因为承诺应该是,这有点做作,但我希望您能理解我的意思:

PS将全局对象附加到窗口是一个坏主意,如果可能的话不应该这样做,这只是展示了一个使用流的快速示例…

window.attempts = 0;
window.maxAttempts = 10;
window.globalThing = true;
function createSlot() {
return new Promise((resolve, reject) => {
    if (!this.checkIsReady()) {
      reject(new Error('Global isnt ready yet'));
    }
    // more stuff here but going to resolve a string for simplicity sake
    resolve('successful!');
}).then((pass) => {
    return pass;
  }, (fail) => {
    window.attempts ++;
    //If within attempts, try again
    if(window.attempts < window.maxAttempts){
      //Chain a new promise to resolve with a timeout of 500ms
      return new Promise((resolve, reject) => {
         setTimeout(() => {
            resolve()
         }, 500);
      }).then(() => {
         //Then try again
         return createSlot();
      })
    }
    else {
      //else fail out with reason
      return fail;
    }
  });
}