Javascript 承诺:将相同的承诺链接 n 次,然后做其他事情

Javascript Promises: Chain same promise n times, then do something else

我有一个返回承诺的函数,可以做一些异步的事情,我们称它为 functionToRepeat()

我正在尝试编写函数 repeatFunction(amount) ,以便它启动承诺,等待完成,再次启动,等待完成,等等给定的次数。这个 repeatFunction(amount) 也应该是 thenable 的,这样我就可以在它执行后链接其他东西。

这是我的尝试:

function functionToRepeat(){
  let action = new Promise(function(resolve,reject){
    setTimeout(function(){
      console.log("resolved!");
      resolve()}
    ,1000);
  })
  return action
}

function repeatFunction(amount) {
  if(amount==0){
    return Promise.resolve();
  }
  return functionToRepeat().then(function(){
    repeatFunction(amount-1);
  });
}

repeatFunction(5).then(function(){
 console.log("DONE!");
})

这成功地链接了我的承诺(或者它接缝,我在控制台中每秒得到一个 "resolved!")。 但是 .then() 我尝试在我的 repeatFunction(5) 之后链接发生在第一个承诺结束之后,而不是在所有 5 个承诺结束之后!

所以在我的控制台中我得到:

解决! 完毕! 解决! 解决! 解决! 已解决!

我做错了什么,我应该改变什么?

您在拨打 repeatFunction(amount-1)

时错过了 return
function functionToRepeat(){
  let action = new Promise(function(resolve,reject){
    setTimeout(function(){
      console.log("resolved!");
      resolve()}
    ,1000);
  })
  return action
}

function repeatFunction(amount) {
  if(amount==0){
    return Promise.resolve();
  }
  return functionToRepeat().then(function(){
    return repeatFunction(amount-1); // Added return
  });
}

repeatFunction(5).then(function(){
 console.log("DONE!");
})

https://plnkr.co/edit/93T6B4QkBv0mYS4xPw0a?p=preview

我想你快到了,但是你必须在函数的 then 块中再次 return repeatFunction 才能重复。

return functionToRepeat().then(function(){
    return repeatFunction(amount-1);
  });
}

如果你有一个then,但没有return任何东西,那么它只会解决上面的承诺。事情就是这样。

let loopP = (n, f, ...args) => {
  let p = f(...args);
  p.then(res => {
    if (n - 1) {
      loopP(n - 1, f, res);
    }
  });
};

其中n是迭代次数,f是要调用的Promise返回函数。对 f 的每次连续调用都会在解析时传递前一次调用的结果。

例如...

let addOneP = i => {
  console.log(i + 1);
  return Promise.resolve(i + 1);
};

loopP(5, addOneP, 0);
// logs:
// 1
// 2
// 3
// 4
// 5

简单的怎么样:

function repeat(func, times) {
  var promise = Promise.resolve();
  while (times-- > 0) promise = promise.then(func);
  return promise;
}

测试时:

function oneSecond() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      console.log("tick");
      resolve();
    }, 1000);
  });
}

repeat(oneSecond, 5).then(function () {
    console.log("done");
});

此输出在 5 秒内生成:

tick
tick
tick
tick
tick
done

您可以通过简单的 while 循环使用 async/await。这让你在 Asyncland 中允许你在重复的函数完成后继续链接

async function asyncRepeat (f, n) {
  while (n-- > 0)
    await f()
}

asyncRepeat(functionToRepeat, 5).then(() => {
  console.log('done')
})

// some value
// some value
// some value
// some value
// some value
// done

这是垃圾。您只能使用副作用函数作为 asyncRepeatf 参数。所以登录到控制台是可行的,但是如果你真的想用那个值做些什么呢?

这是对 asyncRepeat 的更新,允许您通过重复应用输入函数(在本例中为 asyncDouble

粗体中的重要变化)

async function asyncRepeat (f, n<b>, x</b>) {
  while (n-- > 0)
    <b>x = </b>await f(<b>x</b>)
  return <b>x</b>
}

function <b>asyncDouble</b> (<b>x</b>) {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log('x is currently: %d', x)
      resolve(<b>x * 2</b>) // resolve an actual value
    }, 1000)
  })
}

asyncRepeat(asyncDouble, 5<b>, 2</b>).then(result => {
  console.log('result: %d', result)
})

// x is currently: 2
// x is currently: 4
// x is currently: 8
// x is currently: 16
// x is currently: 32
// result: 64

您可能会发现 relign useful for this kind of thing. Here's your example written with relign series and relign setTimeout

const fnToRepeat = () =>
  relign.setTimeout(() => console.log("resolved!"), 1000);

relign.series((new Array(5)).fill(fnToRepeat))
  .then(() => console.log('done'));

我想要类似的东西,所以我在 (https://repl.it/@turlockmike/BriskLovableLinuxkernel)

处写了一个通用函数
function repeat(fn, times) {
  if (times == 1) {
    return fn()
  } else {
    return new Promise(function(resolve, reject) {
      return fn().then(function() {
        return resolve(repeat(fn,times - 1))
      })
    })
  }
}

用法

function doSomething() {
  return new Promise(function(resolve, reject) {
     //do something interested here
     setTimeout(function(){
       console.log("resolved!");
       resolve()}
     ,1000);
  })
}

repeat(doSomething, 5).then(() => {
  console.log("all Done!")
}) 

const http = require('http');
const https = require('https');
const { t, d, r } = require('minimist')(process.argv.slice(2));

const checkRoot = config => {
  const { delaySeconds, rootUrl } = config ? config : { delaySeconds: 6 };
  const delay = delaySeconds * 1000;
  const protocolString = rootUrl.split(':')[0];
  const protocol = {
    http: http,
    https: https,
  };
  return new Promise(res => {
    setTimeout(() => {
      protocol[protocolString]
        .get(rootUrl, resp => {
          let data = '';
          resp.on('data', chunk => {
            data += chunk;
          });
          resp.on('end', () => {
            res({ success: data.includes('<!doctype html>') });
          });
        })
        .on('error', err => {
          console.log(`Error: ${err.message}`);
          res({ success: false });
        });
    }, delay);
  });
};
const repeatChecking = async ({ times, delaySeconds, rootUrl }) => {
  let isReady = false;
  console.log(
    `will try ${times}, and with ${delaySeconds} seconds delay in between for ${rootUrl}`
  );
  let i = 1;
  while (i <= times) {
    if (isReady === true) {
      break;
    }
    const res = await checkRoot({ delaySeconds, rootUrl }).then();
    isReady = res.success;
    console.log(`testing ${i}, status: root ready => ${res.success}`);
    i++;
  }
  if (isReady) {
    console.log('Done, root is ready');
    return;
  }
  process.stdout.write('ERROR: root could not be reached\n');
  process.exit(1);
};

repeatChecking({ times: t, delaySeconds: d, rootUrl: r });