javascript - 如何处理这种 JavaScript Promise 相关情况?

标签 javascript node.js es6-promise

我有以下 javascript 脚本。我正在尝试为区 block 链的工作原理构建一个示例脚本。我将所有 block 数据存储在级别数据库中。

const SHA256 = require('crypto-js/sha256');
var levelDB = require('./levelSandbox');

class Block{
    constructor(data){
    this.hash = "",
    this.height = 0,
    this.body = data,
    this.time = 0,
    this.previousBlockHash = ""
    }
}

class Blockchain{

    constructor(levelDB){
        this.levelDB = levelDB;
        this.blocksInLevelDB = {};
        this.chain = {};

        this.getBlockHeight()
            .then(height => {
                if(!height){
                    this.addBlock(new Block("First block in the chain - Genesis block"));
                }
            })        
    }

    // Method for adding new block
    addBlock(newBlock){
        this.getBlockHeight()
            .then(height => {
                console.log('block height is: ', height);
                console.log('blocksInLevelDB: ', this.blocksInLevelDB);

                // Set block hight
                newBlock.height = height;

                // Set UTC timestamp
                newBlock.time = new Date().getTime().toString().slice(0,-3);

                // Set previous block hash
                if(height > 0){
                    let blockData = JSON.parse(this.blocksInLevelDB[height-1]);
                    newBlock.previousBlockHash = blockData.hash;
                }

                // Block hash with SHA256 using newBlock and converting to a string
                newBlock.hash = SHA256(JSON.stringify(newBlock)).toString();

                console.log('newBlock obj: ',newBlock);

                // Adding block object to chain & save in level db
                this.levelDB.addLevelDBData(height, JSON.stringify(newBlock))
                    .then(console.log('Block added to level db'))
                    .catch(function(err){console.log('Error in adding new block: ', err)})


            })
    }

    // Get block height
    getBlockHeight(){
        return this.levelDB.getAllDataFromLevelDB()      
            .then(data => {
                let blockHeight = data.length;
                for (const elem of data){
                    this.blocksInLevelDB[elem.key] = elem.value;
                }
                return blockHeight;
            })
            .catch(function(err){
                return err;
            });
    }
}

正常情况下一切正常,除了一些情况,比如 -

案例.1 - 当级别 DB 没有数据(空)时,如果我运行以下代码,则只有一条记录插入到级别 DB,而不是两条。

var blockChain = new Blockchain(levelDB);
blockChain.addBlock(new Block('Second block in the chain'));

但是,如果我像这样修改上面的代码 -

var blockChain = new Blockchain(levelDB);
setTimeout(function(){ 
    blockChain.addBlock(new Block('Second block in the chain'));
}, 3000);

然后它工作正常(插入两条记录)。

案例.2 - 当 Level DB 有不止一条记录时 & 如果我尝试添加一条记录,它工作正常。例如。

var blockChain = new Blockchain(levelDB);
blockChain.addBlock(new Block('Third block in the chain'));

但是当我尝试添加多条记录时,只有一条记录被插入(最后一条)。例如。

var blockChain = new Blockchain(levelDB);
blockChain.addBlock(new Block('Third block in the chain'));
blockChain.addBlock(new Block('Fourth block in the chain'));
blockChain.addBlock(new Block('Fifth block in the chain'));

我知道这是因为我对 getBlockHeight() 的所有调用都异步执行并获得相同数量的记录(区 block 链高度)的 promise (异步性质)。因此,在添加新 block 时,所有记录都使用相同的键插入并相互覆盖。但是,无法理解处理这种情况的正确方法是什么。

最佳答案

好的,这是粗略的执行顺序:

new Blockchain(levelDB);
this.levelDB = levelDB;      // constructor
this.blocksInLevelDB = {};   // constructor
this.chain = {};             // constructor
this.getBlockHeight()        // ASYNC, constructor
|    blockChain.addBlock(new Block('Second block in the chain'));
|    this.getBlockHeight()   // ASYNC, called by ^
|    |
L----+--- if (!height)       // true
     |    this.addBlock(new Block("First blo..
     |    this.getBlockHeight()                              // ASYNC
     |    |
     L--- +---> ... this.levelDB.addLevelDBData(height, ...) // ASYNC
          |         // ^ second block is added, at height 0
          |
          L---> ... this.levelDB.addLevelDBData(height, ...)
                    // ^ first block is added, again at height 0

为避免这种情况,您可能也应该为您的 BlockChain 类使用异步模式。

类似于:

let blockChain = new BlockChain(levelDB);

blockChain.init()
    .then(() =>
        blockChain.addBlock(
            new Block('Second block in the chain')))
    .catch(...);

为此,您需要定义一个 init() 方法来检查高度、插入第一个 block 并返回一个 Promise

关于javascript - 如何处理这种 JavaScript Promise 相关情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53580485/

相关文章:

javascript - Promise 仅返回已解析的值

javascript - 在 Javascript 中测试集合成员资格的运算符

javascript - 我可以减少这个 Javascript 代码吗?

javascript - 在进行获取调用之前检查条件

javascript - Node 数组范围问题

node.js - 如何将连接用作具有类型的独立对象?

javascript - 导出 Promise API 调用以供重用

javascript - 使用 Jquery 对齐轮播元素

javascript - jQuery show() 不是函数 - 用于添加 DOM 元素

node.js - 机器人无法识别 LUIS 意图