如何突破这个Promise for loop?

时间:2019-09-02 09:49:30

标签: javascript node.js ecmascript-6 promise es6-promise

编辑:我知道如何使用async / await使它正常工作,但不幸的是,由于它不受广泛支持(尤其是iOS 10,Internet Explorer等),我无法使用它。所以我只需要一个承诺。

我对Promises非常陌生,所以被困住了。我有这个for循环,只要我等于2(例如),我就想打破它。我曾尝试放置->,但仍继续进行到reject。我希望它在满足我的条件时停止。

i<10

当前输出:

for (let i = 0, p = Promise.resolve(); i < 10; i++) {
  p = p.then(_ => new Promise((resolve, reject) => {
    setTimeout(function() {
      console.log(i);
      if (i == 2) {
        reject("BREAK HERE");
      } else {
        resolve();
      }
    }, Math.random() * 1000)
  })).catch(err => {
    console.log(err);
  });
}

我希望它是:

0
1
2
BREAK HERE
3
4
5
6
7
8
9

6 个答案:

答案 0 :(得分:0)

删除catch,否则将捕获并处理错误。要记录日志而不是错误,请使用console.log

try {

  for (let i = 0, p = Promise.resolve(); i < 10; i++) {
    p = p.then(_ => new Promise((resolve, reject) => {
      setTimeout(function() {
        console.log(i);
        if (i == 2) {
          reject(console.log("BREAK HERE"));
        } else {
          resolve();
        }
      }, Math.random() * 1000)
    }));
  }

} catch (e) {}

答案 1 :(得分:0)

无论如何,您的代码将始终执行10次,因为setTimeout是异步操作,并且直到满足您的条件reject("BREAK HERE")时,已经保证的链接都已链接十次。

这是可以做的,尽管看起来很乱:(

for (let i = 0, p = Promise.resolve(); i < 10; i++) {
  p = p.then(data => new Promise((resolve, reject) => {
    setTimeout(function() {
      if(data && data.isRejected){
        resolve({ isRejected: true })
        return;
      }
      console.log(i);
      if (i == 2) {
        reject("BREAK HERE");
      } else {
        resolve({});
      }
    }, Math.random() * 1000)
  })).catch(err => {
    console.log(err);
    /* add this line */
    return { isRejected: true };
  });
}

从catch中返回一个对象(而不是抛出)将把诺言标记为已解决。 docs中的更多内容 这将为您提供所需的结果

答案 2 :(得分:0)

据我了解,您的问题是,您想在宣誓之后顺序履行一个诺言。然后,您想在第一个承诺失败后立即中止。

为确保执行顺序,尽管您失去了并发运行时的实际好处,但必须在for循环中这样做。此代码将顺序运行:

const delay = async () => new Promise((resolve) => setTimeout(() => resolve(), Math.random() * 1e3);

const myUpload = async (file) => {
    await delay();

    if (file === 2) {
        return Promise.reject(`COULD NOT UPLOAD ${file}`);
    } else {
        console.log("uploaded file", file);

        return;
    }

};

const uploadFilesSequentually = async (files) => {
    for (const file of files) {
        await myUpload(file); // this will create, and wait for the promise to finish or fail, only then the for loop continues
    }
};

如果您不关心执行顺序并且可以考虑并发性,那么我会执行以下操作:

const promises = myFiles.map(myUpload); // all promises are now pending and will resolve in different orders
Promise.all(promises) // returns its own promise then resolves once all of them have succeded or is rejected as soon as one is rejected
    .then((result) => console.log("everything uploaded"))
    .catch(console.error);

Promise.all的结果将保持结果的顺序。因此,即使第三个promise在第一个promise之前解决,结果也将是[resultPromise1, resultPrimise2, resultPromise3, ... ]

答案 3 :(得分:0)

就目前而言,我最终使用了另一种方式来实现这一目标而没有承诺:

var i=0;

function fetchNext(){
    if (i==2) {
        console.log("BREAK HERE");
    } else {
        setTimeout(function () {
            console.log(i);
            i++;
            fetchNext();
        }, Math.random() * 1000);
    }
}

fetchNext();

答案 4 :(得分:0)

只要不解决,序列就会停止

for (let i = 0, p = Promise.resolve(); i < 10; i++) {
  p = p.then(_ => new Promise((resolve, reject) => {
    setTimeout(function() {
      console.log("i",i);
      if (i == 2) {
        console.log("break here")
        
      } else {
        resolve();
      }
    }, Math.random() * 1000)
  })).catch(err => {
    console.log("err",err);
  });
}

但是由于这段代码本身打算对异步调用进行排序,所以应该考虑这样做:

// repeated call
next(
  0/*state*/, 
  i=>i<2/*match*/, 
  i=>i+1/*increment*/,     
  asyncCallPromisefied/*promise|promise[]*/, 
  [0]/*args*/
)
.catch(console.log)


// traverse array
next(
  0/*state*/, 
  i => i < 6/*match*/, 
  i => i + 1/*increment*/,
  asyncChain()/*promise|promise[]*/, 
  [0]/*args*/,
  0/*[promise[] index]*/
)
.catch(console.log)


// helper
function next(state, match, increment, action, args, pointer = 0/**inactive**/){
  if(match(state))
  if(Array.isArray(action)){
     
     return pointer < action.length
      ? action[pointer](...args)
      .then(i => next(
        increment(state), 
        match, 
        increment, 
        action, 
        [i],
        pointer + 1
      ))
      : undefined;
  } else {
    return action(...args)
    .then(i => next(
      increment(state), 
      match, 
      increment, 
      action, 
      [i]
    ))
  }
}



// wrapper
function asyncCall(i, callback){ 
  return setTimeout(() => {
    console.log(i == 2 ? 'break here': i);
    callback(null, ++i);
  }, Math.random() * 1000)
}

function asyncCallPromisefied(i){
  return new Promise(function(resolve, reject){
    asyncCall(i, function(err, args){
      if(err){
        reject(err)
      } else {
        resolve(args)
      }
    })
  })
}

function asyncChain(){return [
  function(i){console.log("chain",i);return Promise.resolve(i)},
  function(i){console.log("chain",i);return Promise.resolve(i)},
 function(i){console.log("chain",i);return Promise.resolve(i)},
  asyncCallPromisefied,
  function(i){console.log("chain",i);return Promise.resolve(i)},
]}

答案 5 :(得分:0)

删除循环中的WARNING: [pool www] server reached pm.max_children setting (5), consider raising it ,然后再处理。

.catch