简体   繁体   中英

JavaScript Array filter with async/await

The following function:

async function getPendingTransactions(address){
    var pendingBlock = await web3.eth.getBlock('pending');
    var i = 0;
    var pendingTransactions = await pendingBlock.transactions.filter(async function(txHash)  {
        var tx = await web3.eth.getTransaction(txHash);
        console.log(tx);
        if(tx != null) {
            return tx.from==address && tx.to == CONTRACT_ADDRESS;
        }
    });
    console.log(pendingTransactions);   
    return pendingTransactions;
}

The filter does not work and all transactions are displayed (console.log), and the filter loops seems to be processed afterwards. I guess it is a async/await problem. How can I keep the the filter synchronous?

You can't use an async function as a filter callback, because:

  1. filter won't wait for the promises to be settled, and

  2. async functions always return promises, and promises like all non- null objects are truthy, so as far as filter is concerned you're returning a flag saying you should keep the element

In this case, you can use Promise.all to wait for all the transactions to be retrieved and then filter the results; see comments:

async function getPendingTransactions(address) {
    const pendingBlock = await web3.eth.getBlock("pending");
    // *** Get the transactions by creating an array of promises and then waiting
    // via `await` for all of them to settle
    const transactions = await Promise.all(
        pendingBlock.transactions.map(txHash => web3.eth.getTransaction(txHash))
    );
    // *** Filter them
    const pendingTransactions = transactions.filter(
        tx => tx && tx.from == address && tx.to == CONTRACT_ADDRESS
    );
    return pendingTransactions;
}

All of the calls to web3.eth.getTransaction will be started in parallel, then we wait for all of them to settle via await Promise.all(/*...*/) , then filter the result and return it.

Solution below is using iter-ops library, which supports async filter :

async function getPendingTransactions(address) {
    const pendingBlock = await web3.eth.getBlock('pending');
    return pipeAsync(
        pendingBlock.transactions,
        filter(async txHash => {
            const tx = await web3.eth.getTransaction(txHash);
            console.log(tx);
            if(tx != null) {
                return tx.from == address && tx.to == CONTRACT_ADDRESS;
            }
        })
    );
}

Function getPendingTransactions will return AsyncIterable<Transaction> , which you can easily loop through:

for await (const t of getPendingTransactions('address')) {
    console.log(t); // transaction details
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM