0

I have this function where I disabled eslint warning but I would like to improve the code. I understand that I should use promise.All(), but I am unsure how to proceed since I have two await in the for loop.

const getBatchLogsByHash = async (
  chainId: number,
  rpc: string,
  batch: BlockRange,
) => {
  const firstBlock = batch.startBlock;
  const lastBlock = batch.endBlock;
  const logs: Array<Log> = [];
  /* eslint-disable no-await-in-loop */
  for (let i = firstBlock; i <= lastBlock; i += 1) {
    const block = await ethers.fetchBlock(chainId, rpc, i);
    const blockLogs = await ethers.fetchLogsByBlockHash(
      chainId,
      rpc,
      block.hash,
    );
    logs.push(...blockLogs);
  }
  return logs;
};

Thanks for the help

1
  • Depends on what you need. If you use some sort of Promise.all instead of your for-loop, you have no guarantee whatsoever, in what order the requests are executed. Ie your logs may appear in arbitrary order ... Commented Jan 20, 2023 at 14:21

1 Answer 1

1

You can use await inside the promise executor in order to wait before you resolve the promise. Promise.all then allows you to execute the lastBlock - firstBlock + 1 ethers operations in parallel. Since the order in which they finish cannot be predicted, you cannot use logs.push(...blockLogs). Use concat instead to concatenate the blockLogs to which the individual promises resolve in the order in which you started these promises.

var promises = [];
for (let i = firstBlock; i <= lastBlock; i += 1)
  promises.push(new Promise(async function(resolve, reject) {
    const block = await ethers.fetchBlock(chainId, rpc, i);
    const blockLogs = await ethers.fetchLogsByBlockHash(
      chainId,
      rpc,
      block.hash,
    );
    resolve(blockLogs);
  }));
var logs = Array.prototype.concat.call(...await Promise.all(promises));
return logs;

But the following simpler code using .then would be equivalent:

var promises = [];
for (let i = firstBlock; i <= lastBlock; i += 1)
  promises.push(ethers.fetchBlock(chainId, rpc, i).then(
    block => ethers.fetchLogsByBlockHash(
      chainId,
      rpc,
      block.hash,
    )
  ));
var logs = Array.prototype.concat.call(...await Promise.all(promises));
return logs;
Sign up to request clarification or add additional context in comments.

2 Comments

As a quick note, I had to use this syntax to get rid of any warning var logs = ([] as any[]).concat(...await Promise.all(promises));
You could also use var logs = (await Promise.all(promises)).flat() docs

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.