重复 Promise 直到它没有被拒绝或达到超时

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

我仍然是一个 Promise 菜鸟,我正在努力弄清楚如何让我的 Promise 重演。

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

由于 Promises 是异步的,我真的不想使用 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'));

编辑:基于当前反馈的函数:

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

您可以尝试链接调用,正如 promises 应该的那样,这有点做作,但我希望您明白我的意思:

PS 将全局对象附加到 windows 是一个坏主意,如果可能的话不应该这样做,这只是展示了一个使用您的流程的简单示例...

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

正如 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'));