【问题标题】:How handle this JavaScript Promise related situation?如何处理这种与 JavaScript Promise 相关的情况?
【发布时间】:2018-12-02 13:02:23
【问题描述】:

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

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() 的所有调用都异步执行并获得相同数量的记录(区块链高度)。因此,在添加新块时,所有记录都使用相同的键插入并相互覆盖。但是,无法理解处理这种情况的正确方法是什么。

【问题讨论】:

  • 请注意,如果使用箭头函数,则不需要bind(this)
  • 我对最新的酷 js 技巧不太熟悉。所以,用老派的方式管理一切。不过感谢这个提示。我将使用箭头函数更新我的代码。
  • addBlock 应该是 return 它的承诺。
  • @Bergi - 记下来。

标签: javascript node.js es6-promise


【解决方案1】:

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

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() 方法来检查高度、插入第一个块并返回Promise

【讨论】:

  • 不要忘记return 回调中的addBlock() 承诺
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-15
  • 2014-05-17
  • 1970-01-01
  • 1970-01-01
  • 2012-01-04
  • 2016-07-27
  • 1970-01-01
相关资源
最近更新 更多