节点JS:数组循环和函数不了解回调和承诺如何工作

时间:2018-01-20 06:46:46

标签: javascript node.js callback promise

回调和承诺概念的新概念。我正在尝试读取正确返回地址的目录的内容,但此代码只打印console.log(value)和函数getAccount中的console.log“gettin info ...”但是无处打印余额api正在关闭并且该过程完成,我不明白这一点,因为地址正在传递,第一个console.log正在函数内打印,但没有做进一步的工作。当我删除fs.readdir和files.foreach并将单个值传递给getAccount时,它的工作完全正常。没有错误或错误,它是一个运行时错误,我猜测与回调相关

'use strict';
const RippleAPI = require('ripple-lib').RippleAPI;
const testFolder = '/home/ripple/.keystore';
const fs = require('fs');
const api = new RippleAPI({server: 'wss://s1.ripple.com'});

function getAccount(address) {
        var balance = 0.0;
        console.log("getting info  for :"+address);
        return api.getAccountInfo(address).then(info => {
        var balance = info.xrpBalance;
        console.log("balance of "+address+" is "+balance);
        return balance;
        });
}

api.connect().then(() =>  {
        fs.readdir(testFolder, function(err, files) {
//      console.log("Total no of wallets : "+files.length);
//      for (var i =3000, len=3200; i < len; i++) {
//              var ad = files[i];
//              console.log(ad + "\t" + typeof(ad));
//              if(!xwallets.includes(ad))
                files.forEach(function(value) {
                        getAccount(value).then(balance => {console.log(balance); });
                        console.log(value);
                });
//              console.log("running for index : "+i+" filedata :"+files[i]);
//      }
        });
//      console.log(balance);
}).then(() => {
        return api.disconnect();
}).then(() => {
        console.log("done and disconnected");
}).catch(console.error);

1 个答案:

答案 0 :(得分:1)

您真的不想将返回承诺的异步操作与进行直接回调的异步操作混合在一起。在这样混合时编写好的健壮代码很难。因此,由于您已经在许多操作中使用了承诺,因此最好采用剩余的异步操作和&#34; promisify&#34;他们所以你可以将它们与承诺一起使用。然后,您可以利用所有干净的错误传播和承诺的链接。

然后,其次,您必须确保循环中的所有异步操作都正确链接到父承诺。为了做到这一点,我们将把循环中getAccount()的承诺累积到一系列承诺中。然后,在循环之后,我们可以告诉他们何时使用Promise.all()完成所有操作,然后从readdir()返回该承诺,以便将它们全部正确地链接到父承诺。

然后,这将确保循环内的所有内容在父结算之前和调用api.disconnect()之前完成。

这就是看起来的样子:

'use strict';
const RippleAPI = require('ripple-lib').RippleAPI;
const testFolder = '/home/ripple/.keystore';
const fs = require('fs');
const api = new RippleAPI({server: 'wss://s1.ripple.com'});

function getAccount(address) {
    var balance = 0.0;
    console.log("getting info  for :"+address);
    return api.getAccountInfo(address).then(info => {
        var balance = info.xrpBalance;
        console.log("balance of "+address+" is "+balance);
        return balance;
    });
}

// promisify readdir
const readdir = util.promisify(fs.readdir);

api.connect().then(() =>  {
    return readdir(testFolder).then(function(files) {
        const promises = [];
        files.forEach(function(file) {
            console.log(file);
            promises.push(getAccount(file).then(balance => {
                console.log(balance); 
                // make balance be the resolved value for this promise
                return balance;
            }));
        });
        // make sure we are waiting for all these promises to be done
        // by chaining them into the parent promise
        return Promise.all(promises);
    });
}).then(balances => {
    // process balances array here
    console.log(balances);
    return api.disconnect();
}, err => {
    // disconnect, even in the error case, but preserve the error
    console.error(err);
    return api.disconnect().then(() => {throw err;})
}).then(() => {
    console.log("done and disconnected");
});

所做的更改摘要:

  1. 宣传fs.readdir(),以便我们可以使用诺言
  2. 更改我们如何致电readdir()以使用承诺
  3. getAccount()内的.forEach()个承诺收集到一系列承诺中
  4. 添加return Promise.all(promises)以便我们等待所有这些承诺完成并将其链接到父承诺
  5. 使balance成为.forEach()循环中每个承诺的已解析值,即使在记录其值后
  6. 即使在错误情况下
  7. ,也要确保我们正在调用api.disconnect()
  8. 记录错误后,将错误值保留为拒绝原因