国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

以太坊開發(fā)實(shí)戰(zhàn)學(xué)習(xí)-Web3.js(九)

luckyyulin / 3063人閱讀

摘要:首先我們需要要記住,以太坊是由共享同一份數(shù)據(jù)的相同拷貝的節(jié)點(diǎn)構(gòu)成的。你可以運(yùn)行你自己的以太坊節(jié)點(diǎn)來(lái)作為。在你部署智能合約以后,它將獲得一個(gè)以太坊上的永久地址。如果你還記得第二課,在以太坊上的地址是。

通過(guò)前邊的學(xué)習(xí),DApp 的 Solidity 合約部分就完成了。現(xiàn)在我們來(lái)做一個(gè)基本的網(wǎng)頁(yè)好讓你的用戶能玩它。 要做到這一點(diǎn),我們將使用以太坊基金發(fā)布的 JavaScript 庫(kù) —— Web3.js.
一、Web3.js簡(jiǎn)介 什么是 Web3.js?

還記得么?以太坊網(wǎng)絡(luò)是由節(jié)點(diǎn)組成的,每一個(gè)節(jié)點(diǎn)都包含了區(qū)塊鏈的一份拷貝。當(dāng)你想要調(diào)用一份智能合約的一個(gè)方法,你需要從其中一個(gè)節(jié)點(diǎn)中查找并告訴它:

1、智能合約的地址

2、你想調(diào)用的方法,以及

3、你想傳入那個(gè)方法的參數(shù)

以太坊節(jié)點(diǎn)只能識(shí)別一種叫做 JSON-RPC 的語(yǔ)言。這種語(yǔ)言直接讀起來(lái)并不好懂。當(dāng)你你想調(diào)用一個(gè)合約的方法的時(shí)候,需要發(fā)送的查詢語(yǔ)句將會(huì)是這樣的:

// 哈……祝你寫所有這樣的函數(shù)調(diào)用的時(shí)候都一次通過(guò)
// 往右邊拉…… ==>
{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from":"0xb60e8dd61c5d32be8058bb8eb970870f07233155","to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","gas":"0x76c0","gasPrice":"0x9184e72a000","value":"0x9184e72a","data":"0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}],"id":1}

幸運(yùn)的是 Web3.js 把這些令人討厭的查詢語(yǔ)句都隱藏起來(lái)了, 所以你只需要與方便易懂的 JavaScript 界面進(jìn)行交互即可。

你不需要構(gòu)建上面的查詢語(yǔ)句,在你的代碼中調(diào)用一個(gè)函數(shù)看起來(lái)將是這樣:

CryptoZombies.methods.createRandomZombie("Vitalik Nakamoto")
  .send({ from: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", gas: "3000000" })

我們將在接下來(lái)的幾章詳細(xì)解釋這些語(yǔ)句,不過(guò)首先我們來(lái)把 Web3.js 環(huán)境搭建起來(lái)

準(zhǔn)備工作

取決于你的項(xiàng)目工作流程和你的愛(ài)好,你可以用一些常用工具把 Web3.js 添加進(jìn)來(lái):

// 用 NPM
npm install web3

// 用 Yarn
yarn add web3

// 用 Bower
bower install web3

// ...或者其他。

甚至,你可以從 github直接下載壓縮后的 .js 文件 然后包含到你的項(xiàng)目文件中:


    
    
  
  

  

二、Web3提供者

現(xiàn)在我們的項(xiàng)目中有了Web3.js, 來(lái)初始化它然后和區(qū)塊鏈對(duì)話吧。

首先我們需要 Web3 Provider.

要記住,以太坊是由共享同一份數(shù)據(jù)的相同拷貝的 節(jié)點(diǎn) 構(gòu)成的。 在 Web3.js 里設(shè)置 Web3 的 Provider(提供者) 告訴我們的代碼應(yīng)該和 哪個(gè)節(jié)點(diǎn) 交互來(lái)處理我們的讀寫。這就好像在傳統(tǒng)的 Web 應(yīng)用程序中為你的 API 調(diào)用設(shè)置遠(yuǎn)程 Web 服務(wù)器的網(wǎng)址。

你可以運(yùn)行你自己的以太坊節(jié)點(diǎn)來(lái)作為 Provider。 不過(guò),有一個(gè)第三方的服務(wù),可以讓你的生活變得輕松點(diǎn),讓你不必為了給你的用戶提供DApp而維護(hù)一個(gè)以太坊節(jié)點(diǎn)— Infura.

Infura

Infura 是一個(gè)服務(wù),它維護(hù)了很多以太坊節(jié)點(diǎn)并提供了一個(gè)緩存層來(lái)實(shí)現(xiàn)高速讀取。你可以用他們的 API 來(lái)免費(fèi)訪問(wèn)這個(gè)服務(wù)。 用 Infura 作為節(jié)點(diǎn)提供者,你可以不用自己運(yùn)營(yíng)節(jié)點(diǎn)就能很可靠地向以太坊發(fā)送、接收信息。

你可以通過(guò)這樣把 Infura 作為你的 Web3 節(jié)點(diǎn)提供者:

var web3 = new Web3(new Web3.providers.WebsocketProvider("wss://mainnet.infura.io/ws"));

不過(guò),因?yàn)槲覀兊?DApp 將被很多人使用,這些用戶不單會(huì)從區(qū)塊鏈讀取信息,還會(huì)向區(qū)塊鏈 入信息,我們需要用一個(gè)方法讓用戶可以用他們的私鑰給事務(wù)簽名

注意: 以太坊 (以及通常意義上的 blockchains )使用一個(gè)公鑰/私鑰對(duì)來(lái)對(duì)給事務(wù)做數(shù)字簽名。把它想成一個(gè)數(shù)字簽名的異常安全的密碼。這樣當(dāng)我修改區(qū)塊鏈上的數(shù)據(jù)的時(shí)候,我可以用我的公鑰來(lái) 證明 我就是簽名的那個(gè)。但是因?yàn)闆](méi)人知道我的私鑰,所以沒(méi)人能偽造我的事務(wù)。

加密學(xué)非常復(fù)雜,所以除非你是個(gè)專家并且的確知道自己在做什么,你最好不要在你應(yīng)用的前端中管理你用戶的私鑰。

不過(guò)幸運(yùn)的是,你并不需要,已經(jīng)有可以幫你處理這件事的服務(wù)了: Metamask.

Metamask

Metamask 是 Chrome 和 Firefox 的瀏覽器擴(kuò)展, 它能讓用戶安全地維護(hù)他們的以太坊賬戶和私鑰, 并用他們的賬戶和使用 Web3.js 的網(wǎng)站互動(dòng)(如果你還沒(méi)用過(guò)它,你肯定會(huì)想去安裝的——這樣你的瀏覽器就能使用 Web3.js 了,然后你就可以和任何與以太坊區(qū)塊鏈通信的網(wǎng)站交互了)

作為開發(fā)者,如果你想讓用戶從他們的瀏覽器里通過(guò)網(wǎng)站和你的DApp交互(就像我們?cè)?CryptoZombies 游戲里一樣),你肯定會(huì)想要兼容 Metamask 的。

注意: Metamask 默認(rèn)使用 Infura 的服務(wù)器做為 web3 提供者。 就像我們上面做的那樣。不過(guò)它還為用戶提供了選擇他們自己 Web3 提供者的選項(xiàng)。所以使用 Metamask 的 web3 提供者,你就給了用戶選擇權(quán),而自己無(wú)需操心這一塊。
使用Metamask的web3提供者

Metamask 把它的 web3 提供者注入到瀏覽器的全局 JavaScript對(duì)象web3中。所以你的應(yīng)用可以檢查 web3 是否存在。若存在就使用 web3.currentProvider 作為它的提供者。

這里是一些 Metamask 提供的示例代碼,用來(lái)檢查用戶是否安裝了MetaMask,如果沒(méi)有安裝就告訴用戶需要安裝MetaMask來(lái)使用我們的應(yīng)用。

window.addEventListener("load", function() {

  // 檢查web3是否已經(jīng)注入到(Mist/MetaMask)
  if (typeof web3 !== "undefined") {
    // 使用 Mist/MetaMask 的提供者
    web3js = new Web3(web3.currentProvider);
  } else {
    // 處理用戶沒(méi)安裝的情況, 比如顯示一個(gè)消息
    // 告訴他們要安裝 MetaMask 來(lái)使用我們的應(yīng)用
  }

  // 現(xiàn)在你可以啟動(dòng)你的應(yīng)用并自由訪問(wèn) Web3.js:
  startApp()

})

你可以在你所有的應(yīng)用中使用這段樣板代碼,好檢查用戶是否安裝以及告訴用戶安裝 MetaMask。

注意: 除了MetaMask,你的用戶也可能在使用其他他的私鑰管理應(yīng)用,比如 Mist 瀏覽器。不過(guò),它們都實(shí)現(xiàn)了相同的模式來(lái)注入 web3 變量。所以我這里描述的方法對(duì)兩者是通用的。
實(shí)戰(zhàn)演練

我們?cè)贖TML文件中的 標(biāo)簽前面放置了一個(gè)空的 script 標(biāo)簽。可以把這節(jié)課的 JavaScript 代碼寫在里面。

把上面用來(lái)檢測(cè) MetaMask 是否安裝的模板代碼粘貼進(jìn)來(lái)。請(qǐng)粘貼到以 window.addEventListener 開頭的代碼塊中。

index.html



  
    
    CryptoZombies front-end
    
    
  
  

    
  

三、和合約對(duì)話

現(xiàn)在,我們已經(jīng)用 MetaMask 的 Web3 提供者初始化了 Web3.js。接下來(lái)就讓它和我們的智能合約對(duì)話吧。

Web3.js 需要兩個(gè)東西來(lái)和你的合約對(duì)話: 它的 地址 和它的 ABI

合約地址

在你寫完了你的智能合約后,你需要編譯它并把它部署到以太坊。我們將在下一課中詳述部署,因?yàn)樗蛯懘a是截然不同的過(guò)程,所以我們決定打亂順序,先來(lái)講 Web3.js。

在你部署智能合約以后,它將獲得一個(gè)以太坊上的永久地址。如果你還記得第二課,CryptoKitties 在以太坊上的地址是 YOUR_CONTRACT_ADDRESS

你需要在部署后復(fù)制這個(gè)地址以來(lái)和你的智能合約對(duì)話。

合約ABI

另一個(gè) Web3.js 為了要和你的智能合約對(duì)話而需要的東西是 ABI。

ABI 意為應(yīng)用二進(jìn)制接口(Application Binary Interface)。 基本上,它是以 JSON 格式表示合約的方法,告訴 Web3.js 如何以合同理解的方式格式化函數(shù)調(diào)用。

當(dāng)你編譯你的合約向以太坊部署時(shí)(我們將后邊詳述), Solidity 編譯器會(huì)給你 ABI,所以除了合約地址,你還需要把這個(gè)也復(fù)制下來(lái)。

因?yàn)槲覀冞@一課不會(huì)講述部署,所以現(xiàn)在我們已經(jīng)幫你編譯了 ABI 并放在了名為cryptozombies_abi.js,文件中,保存在一個(gè)名為 cryptozombiesABI 的變量中。

如果我們將cryptozombies_abi.js 包含進(jìn)我們的項(xiàng)目,我們就能通過(guò)那個(gè)變量訪問(wèn) CryptoZombies ABI 。

cryptozombies_abi.js 文件:

var cryptozombiesABI = [
  {
    "constant": false,
    "inputs": [
      {
        "name": "_to",
        "type": "address"
      },
      {
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_zombieId",
        "type": "uint256"
      }
    ],
    "name": "levelUp",
    "outputs": [],
    "payable": true,
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_zombieId",
        "type": "uint256"
      },
      {
        "name": "_kittyId",
        "type": "uint256"
      }
    ],
    "name": "feedOnKitty",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "zombies",
    "outputs": [
      {
        "name": "name",
        "type": "string"
      },
      {
        "name": "dna",
        "type": "uint256"
      },
      {
        "name": "level",
        "type": "uint32"
      },
      {
        "name": "readyTime",
        "type": "uint32"
      },
      {
        "name": "winCount",
        "type": "uint16"
      },
      {
        "name": "lossCount",
        "type": "uint16"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [],
    "name": "withdraw",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "_owner",
        "type": "address"
      }
    ],
    "name": "getZombiesByOwner",
    "outputs": [
      {
        "name": "",
        "type": "uint256[]"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "zombieToOwner",
    "outputs": [
      {
        "name": "",
        "type": "address"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_address",
        "type": "address"
      }
    ],
    "name": "setKittyContractAddress",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_zombieId",
        "type": "uint256"
      },
      {
        "name": "_newDna",
        "type": "uint256"
      }
    ],
    "name": "changeDna",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "ownerOf",
    "outputs": [
      {
        "name": "_owner",
        "type": "address"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "_owner",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "name": "_balance",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_name",
        "type": "string"
      }
    ],
    "name": "createRandomZombie",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "name": "",
        "type": "address"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_to",
        "type": "address"
      },
      {
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "getAllZombies",
    "outputs": [
      {
        "name": "",
        "type": "uint256[]"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "takeOwnership",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_zombieId",
        "type": "uint256"
      },
      {
        "name": "_newName",
        "type": "string"
      }
    ],
    "name": "changeName",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_fee",
        "type": "uint256"
      }
    ],
    "name": "setLevelUpFee",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_zombieId",
        "type": "uint256"
      },
      {
        "name": "_targetId",
        "type": "uint256"
      }
    ],
    "name": "attack",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "_from",
        "type": "address"
      },
      {
        "indexed": true,
        "name": "_to",
        "type": "address"
      },
      {
        "indexed": false,
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "_owner",
        "type": "address"
      },
      {
        "indexed": true,
        "name": "_approved",
        "type": "address"
      },
      {
        "indexed": false,
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "name": "attackResult",
        "type": "bool"
      },
      {
        "indexed": false,
        "name": "winCount",
        "type": "uint16"
      },
      {
        "indexed": false,
        "name": "lossCount",
        "type": "uint16"
      }
    ],
    "name": "AttackResult",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "name": "zombieId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "name": "name",
        "type": "string"
      },
      {
        "indexed": false,
        "name": "dna",
        "type": "uint256"
      }
    ],
    "name": "NewZombie",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  }
]
實(shí)例化Web3.js

一旦你有了合約的地址和 ABI,你可以像這樣來(lái)實(shí)例化 Web3.js。

// 實(shí)例化 myContract
var myContract = new web3js.eth.Contract(myABI, myContractAddress);
實(shí)戰(zhàn)演練

1、在文件的 標(biāo)簽塊中,用 script 標(biāo)簽引入cryptozombies_abi.js,好把 ABI 的定義引入項(xiàng)目。

2、在 里的 四、調(diào)用和合約函數(shù)

我們的合約配置好了!現(xiàn)在來(lái)用 Web3.js 和它對(duì)話。

Web3.js 有兩個(gè)方法來(lái)調(diào)用我們合約的函數(shù): call and send.

call

call 用來(lái)調(diào)用 viewpure 函數(shù)。它只運(yùn)行在本地節(jié)點(diǎn),不會(huì)在區(qū)塊鏈上創(chuàng)建事務(wù)。

復(fù)習(xí): viewpure 函數(shù)是只讀的并不會(huì)改變區(qū)塊鏈的狀態(tài)。它們也不會(huì)消耗任何gas。用戶也不會(huì)被要求用MetaMask對(duì)事務(wù)簽名

使用 Web3.js,你可以如下 call 一個(gè)名為myMethod的方法并傳入一個(gè) 123 作為參數(shù):

myContract.methods.myMethod(123).call()
Send

send創(chuàng)建一個(gè)事務(wù)并改變區(qū)塊鏈上的數(shù)據(jù)。你需要用 send 來(lái)調(diào)用任何非 view 或者 pure 的函數(shù)。

注意: send 一個(gè)事務(wù)將要求用戶支付gas,并會(huì)要求彈出對(duì)話框請(qǐng)求用戶使用 Metamask 對(duì)事務(wù)簽名。在我們使用 Metamask 作為我們的 web3 提供者的時(shí)候,所有這一切都會(huì)在我們調(diào)用 send() 的時(shí)候自動(dòng)發(fā)生。而我們自己無(wú)需在代碼中操心這一切,挺爽的吧。

使用 Web3.js, 你可以像這樣 send 一個(gè)事務(wù)調(diào)用myMethod 并傳入 123 作為參數(shù):

myContract.methods.myMethod(123).send()

語(yǔ)法幾乎 call()一模一樣。

獲取僵尸數(shù)據(jù)

來(lái)看一個(gè)使用 call 讀取我們合約數(shù)據(jù)的真實(shí)例子

回憶一下,我們定義我們的僵尸數(shù)組為 公開(public):

Zombie[] public zombies;

在 Solidity 里,當(dāng)你定義一個(gè) public變量的時(shí)候, 它將自動(dòng)定義一個(gè)公開的 "getter" 同名方法, 所以如果你像要查看 id 為 15 的僵尸,你可以像一個(gè)函數(shù)一樣調(diào)用它: zombies(15).

這是如何在外面的前端界面中寫一個(gè) JavaScript 方法來(lái)傳入一個(gè)僵尸 id,在我們的合同中查詢那個(gè)僵尸并返回結(jié)果

注意: 本課中所有的示例代碼都使用 Web3.js 的 1.0 版,此版本使用的是 Promises 而不是回調(diào)函數(shù)。你在線上看到的其他教程可能還在使用老版的 Web3.js。在1.0版中,語(yǔ)法改變了不少。如果你從其他教程中復(fù)制代碼,先確保你們使用的是相同版本的Web3.js。
function getZombieDetails(id) {
  return cryptoZombies.methods.zombies(id).call()
}

// 調(diào)用函數(shù)并做一些其他事情
getZombieDetails(15)
.then(function(result) {
  console.log("Zombie 15: " + JSON.stringify(result));
});

我們來(lái)看看這里都做了什么
cryptoZombies.methods.zombies(id).call() 將和 Web3 提供者節(jié)點(diǎn)通信,告訴它返回從我們的合約中的 Zombie[] public zombies,id為傳入?yún)?shù)的僵尸信息。

注意這是 異步的,就像從外部服務(wù)器中調(diào)用API。所以 Web3 在這里返回了一個(gè) Promises. (如果你對(duì) JavaScript的 Promises 不了解,最好先去學(xué)習(xí)一下這方面知識(shí)再繼續(xù))。

一旦那個(gè) promiseresolve, (意味著我們從 Web3 提供者那里獲得了響應(yīng)),我們的例子代碼將執(zhí)行 then 語(yǔ)句中的代碼,在控制臺(tái)打出 result。

result 是一個(gè)像這樣的 JavaScript 對(duì)象:

{
  "name": "H4XF13LD MORRIS"S COOLER OLDER BROTHER",
  "dna": "1337133713371337",
  "level": "9999",
  "readyTime": "1522498671",
  "winCount": "999999999",
  "lossCount": "0" // Obviously.
}

我們可以用一些前端邏輯代碼來(lái)解析這個(gè)對(duì)象并在前端界面友好展示。

實(shí)戰(zhàn)演練

我們已經(jīng)把 getZombieDetails 復(fù)制進(jìn)了代碼。

1、先為zombieToOwner 創(chuàng)建一個(gè)類似的函數(shù)。如果你還記得 ZombieFactory.sol,我們有一個(gè)長(zhǎng)這樣的映射:

`mapping (uint => address) public zombieToOwner;

定義一個(gè) JavaScript 方法,起名為 zombieToOwner。和上面的 getZombieDetails 類似, 它將接收一個(gè)id 作為參數(shù),并返回一個(gè) Web3.js call 我們合約里的zombieToOwner 。

2、之后在下面,為 getZombiesByOwner 定義一個(gè)方法。如果你還能記起 ZombieHelper.sol,這個(gè)方法定義像這樣:

function getZombiesByOwner(address _owner)

我們的 getZombiesByOwner 方法將接收 owner 作為參數(shù),并返回一個(gè)對(duì)我們函數(shù) getZombiesByOwner的 Web3.js call

index.html



  
    
    CryptoZombies front-end
    
    
    
  
  

    
  

Promise學(xué)習(xí)

promise異步編程的一種解決方案,比傳統(tǒng)的解決方案–回調(diào)函數(shù)和事件--更合理和更強(qiáng)大。它由社區(qū)最早提出和實(shí)現(xiàn),ES6將其寫進(jìn)了語(yǔ)言標(biāo)準(zhǔn),統(tǒng)一了語(yǔ)法,原生提供了Promise

所謂Promise ,簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才回結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。從語(yǔ)法上說(shuō),Promise是一個(gè)對(duì)象,從它可以獲取異步操作的消息。
Promise 對(duì)象的狀態(tài)不受外界影響

三種狀態(tài):

pending:進(jìn)行中

fulfilled :已經(jīng)成功

rejected 已經(jīng)失敗

狀態(tài)改變:
Promise對(duì)象的狀態(tài)改變,只有兩種可能:

從pending變?yōu)閒ulfilled

從pending變?yōu)閞ejected。

這兩種情況只要發(fā)生,狀態(tài)就凝固了,不會(huì)再變了,這時(shí)就稱為resolved(已定型)

基本用法

ES6規(guī)定,Promise對(duì)象是一個(gè)構(gòu)造函數(shù),用來(lái)生成Promise實(shí)例:

const promist = new Promise(function(resolve,reject){
    if(/*異步操作成功*/){
        resolve(value);
    }else{
        reject(error);
    }
})

resolve函數(shù)的作用是,將Promise對(duì)象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?pending 變?yōu)?resolved),在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去;

reject函數(shù)的作用是,將Promise對(duì)象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?pending 變?yōu)?rejected),在異步操作失敗時(shí)調(diào)用,并將異步操作報(bào)出的錯(cuò)誤,作為參數(shù)傳遞出去。

Promise 實(shí)例生成以后,可以用then 方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)。

promise.then(function(value){
//success
},function(error){
//failure
});

示例:

function timeout(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(resolve,ms,"done");
    });
}
timeout(100).then((value)=>{
    console.log(value);
});
let promise = new Promise(function(resolve,reject){
    console.log("Promise");
    resolve();
});
promise.then(function(){
    console.log("resolved");
});
console.log("Hi!");

//Promise
//Hi!
//resolved
//異步加載圖片
function loadImageAsync(url){
    return new Promise(function(resolve,reject){
        const image = new Image();
        image.onload = function(){
            resolve(image);
        };
        image.onerror = function(){
            reject(new Error("error");
        };
        image.src = url;
    });
}

下面是一個(gè)用Promise對(duì)象實(shí)現(xiàn)的 Ajax 操作的例子。

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log("Contents: " + json);
}, function(error) {
  console.error("出錯(cuò)了", error);
});
五、MetaMask和賬戶

接下來(lái)我們綜合一下——比如我們想讓我們應(yīng)用的首頁(yè)顯示用戶的整個(gè)僵尸大軍。

毫無(wú)疑問(wèn)我們首先需要用 getZombiesByOwner(owner) 來(lái)查詢當(dāng)前用戶的所有僵尸ID。

但是我們的 Solidity 合約需要 owner 作為 Solidity address。我們?nèi)绾文苤缿?yīng)用用戶的地址呢?

獲得MetaMask中的用戶賬戶

MetaMask 允許用戶在擴(kuò)展中管理多個(gè)賬戶。

我們可以通過(guò)這樣來(lái)獲取 web3 變量中激活的當(dāng)前賬戶:

var userAccount = web3.eth.accounts[0]

因?yàn)橛脩艨梢噪S時(shí)在 MetaMask 中切換賬戶,我們的應(yīng)用需要監(jiān)控這個(gè)變量,一旦改變就要相應(yīng)更新界面。例如,若用戶的首頁(yè)展示它們的僵尸大軍,當(dāng)他們?cè)?MetaMask 中切換了賬號(hào),我們就需要更新頁(yè)面來(lái)展示新選擇的賬戶的僵尸大軍。

我們可以通過(guò) setInterval 方法來(lái)做:

var accountInterval = setInterval(function() {
  // 檢查賬戶是否切換
  if (web3.eth.accounts[0] !== userAccount) {
    userAccount = web3.eth.accounts[0];
    // 調(diào)用一些方法來(lái)更新界面
    updateInterface();
  }
}, 100);

這段代碼做的是,每100毫秒檢查一次 userAccount 是否還等于 web3.eth.accounts[0] (比如:用戶是否還激活了那個(gè)賬戶)。若不等,則將 當(dāng)前激活用戶賦值給 userAccount,然后調(diào)用一個(gè)函數(shù)來(lái)更新界面。

實(shí)戰(zhàn)演練

我們來(lái)讓應(yīng)用在頁(yè)面第一次加載的時(shí)候顯示用戶的僵尸大軍,監(jiān)控當(dāng)前 MetaMask 中的激活賬戶,并在賬戶發(fā)生改變的時(shí)候刷新顯示。

1、定義一個(gè)名為userAccount的變量,不給任何初始值。

2、在 startApp()函數(shù)的最后,復(fù)制粘貼上面樣板代碼中的 accountInterval 方法進(jìn)去。

3、將 updateInterface();替換成一個(gè) getZombiesByOwnercall 函數(shù),并傳入 userAccount

4、在 getZombiesByOwner 后面鏈?zhǔn)秸{(diào)用then 語(yǔ)句,并將返回的結(jié)果傳入名為 displayZombies 的函數(shù)。 (語(yǔ)句像這樣: .then(displayZombies);).

我們還沒(méi)有 displayZombies 函數(shù),將于下一章實(shí)現(xiàn)。



  
    
    CryptoZombies front-end
    
    
    
  
  

    
  

六、顯示合約數(shù)據(jù)

如果我們不向你展示如何顯示你從合約獲取的數(shù)據(jù),那這個(gè)教程就太不完整了。

在實(shí)際應(yīng)用中,你肯定想要在應(yīng)用中使用諸如 React 或 Vue.js 這樣的前端框架來(lái)讓你的前端開發(fā)變得輕松一些。不過(guò)要教授 React 或者 Vue.js 知識(shí)的話,就大大超出了本教程的范疇——它們本身就需要幾節(jié)課甚至一整個(gè)教程來(lái)教學(xué)。

所以為了讓 CryptoZombies.io 專注于以太坊和智能合約,我們將使用 JQuery 來(lái)做一個(gè)快速示例,展示如何解析和展示從智能合約中拿到的數(shù)據(jù)。

顯示僵尸數(shù)據(jù)

我們已經(jīng)在代碼中添加了一個(gè)空的代碼塊

, 在 displayZombies 方法中也同樣有一個(gè)。

回憶一下在之前章節(jié)中我們?cè)?startApp() 方法內(nèi)部調(diào)用了 displayZombies 并傳入了 call getZombiesByOwner 獲得的結(jié)果,它將被傳入一個(gè)僵尸ID數(shù)組,像這樣:

[0, 13, 47]

因?yàn)槲覀兿胱屛覀兊?displayZombies 方法做這些事:

1、首先清除 #zombies 的內(nèi)容以防里面已經(jīng)有什么內(nèi)容(這樣當(dāng)用戶切換賬號(hào)的時(shí)候,之前賬號(hào)的僵尸大軍數(shù)據(jù)就會(huì)被清除)

2、循環(huán)遍歷 id,對(duì)每一個(gè)id調(diào)用 getZombieDetails(id), 從我們的合約中獲得這個(gè)僵尸的數(shù)據(jù)。

3、將獲得的僵尸數(shù)據(jù)放進(jìn)一個(gè)HTML模板中以格式化顯示,追加進(jìn) #zombies 里面。

再次聲明,我們只用了 JQuery,沒(méi)有任何模板引擎,所以會(huì)非常丑。不過(guò)這只是一個(gè)如何展示僵尸數(shù)據(jù)的示例而已。

// 在合約中查找僵尸數(shù)據(jù),返回一個(gè)對(duì)象
getZombieDetails(id)
.then(function(zombie) {
  // 用 ES6 的模板語(yǔ)法來(lái)向HTML中注入變量
  // 把每一個(gè)都追加進(jìn) #zombies div
  $("#zombies").append(`
  • Name: ${zombie.name}
  • DNA: ${zombie.dna}
  • Level: ${zombie.level}
  • Wins: ${zombie.winCount}
  • Losses: ${zombie.lossCount}
  • Ready Time: ${zombie.readyTime}
`); });
如何來(lái)展示僵尸元素呢?

在上面的例子中,我們只是簡(jiǎn)單地用字符串來(lái)顯示 DNA。不過(guò)在你的 DApp 中,你將需要把 DNA 轉(zhuǎn)換成圖片來(lái)顯示你的僵尸。

我們通過(guò)把 DNA 字符串分割成小的字符串來(lái)做到這一點(diǎn),每2位數(shù)字代表一個(gè)圖片,類似這樣:

// 得到一個(gè) 1-7 的數(shù)字來(lái)表示僵尸的頭:
var head = parseInt(zombie.dna.substring(0, 2)) % 7 + 1

// 我們有7張頭部圖片:
var headSrc = "../assets/zombieparts/head-" + i + ".png"

每一個(gè)模塊都用 CSS 絕對(duì)定位來(lái)顯示,在一個(gè)上面疊加另外一個(gè)。

如果你想看我們的具體實(shí)現(xiàn),我們將用來(lái)展示僵尸形象的 Vue.js 模塊開源了: 點(diǎn)擊這里.

不過(guò),因?yàn)槟莻€(gè)文件中有太多行代碼, 超出了本教程的討論范圍。我們依然還是使用上面超級(jí)簡(jiǎn)單的 JQuery 實(shí)現(xiàn),把美化僵尸的工作作為家庭作業(yè)留給你了

實(shí)戰(zhàn)演練

我們?yōu)槟銊?chuàng)建了一個(gè)空的 displayZombies 方法。來(lái)一起實(shí)現(xiàn)它。

1、首先我們需要清空 #zombies 的內(nèi)容。 用JQuery,你可以這樣做: $("#zombies").empty();。

2、接下來(lái),我們要循環(huán)遍歷所有的 id,循環(huán)這樣用: for (id of ids) {

3、在循環(huán)內(nèi)部,復(fù)制粘貼上面的代碼,對(duì)每一個(gè)id調(diào)用 getZombieDetails(id),然后用 $("#zombies").append(...) 把內(nèi)容追加進(jìn)我們的 HTML 里面。



  
    
    CryptoZombies front-end
    
    
    
  
  
    

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/24154.html

相關(guān)文章

  • 以太開發(fā)實(shí)戰(zhàn)學(xué)習(xí)-Web3.js(十)

    摘要:如果當(dāng)前在以太坊上有大量掛起事務(wù)或者用戶發(fā)送了過(guò)低的價(jià)格,我們的事務(wù)可能需要等待數(shù)個(gè)區(qū)塊才能被包含進(jìn)去,往往可能花費(fèi)數(shù)分鐘。 接上篇 Web3.js,這節(jié)課繼續(xù)學(xué)習(xí)Web3.js 的相關(guān)知識(shí)。 一、發(fā)送事務(wù) 這下我們的界面能檢測(cè)用戶的 MetaMask 賬戶,并自動(dòng)在首頁(yè)顯示它們的僵尸大軍了,有沒(méi)有很棒? 現(xiàn)在我們來(lái)看看用 send 函數(shù)來(lái)修改我們智能合約里面的數(shù)據(jù)。 相對(duì) call...

    Scott 評(píng)論0 收藏0
  • 以太web3.js文檔翻譯及說(shuō)明

    摘要:這些天,為了錄制以太坊開發(fā)實(shí)戰(zhàn)課程,我準(zhǔn)備把文檔全部翻譯一下并做適當(dāng)?shù)难a(bǔ)充,目前版本已經(jīng)翻譯完成,歡迎大家前往查閱。 這些天,為了錄制以太坊DAPP開發(fā)實(shí)戰(zhàn)課程,我準(zhǔn)備把web3文檔全部翻譯一下(并做適當(dāng)?shù)难a(bǔ)充),目前web3.js 0.20.x 版本 已經(jīng)翻譯完成,歡迎大家前往查閱。 這里還幾個(gè)實(shí)用DEMO,供大家參考: 使用web3.js API在頁(yè)面中轉(zhuǎn)賬 web3.js 0....

    趙春朋 評(píng)論0 收藏0
  • 以太web3.js文檔翻譯及說(shuō)明

    摘要:這些天,為了錄制以太坊開發(fā)實(shí)戰(zhàn)課程,我準(zhǔn)備把文檔全部翻譯一下并做適當(dāng)?shù)难a(bǔ)充,目前版本已經(jīng)翻譯完成,歡迎大家前往查閱。 這些天,為了錄制以太坊DAPP開發(fā)實(shí)戰(zhàn)課程,我準(zhǔn)備把web3文檔全部翻譯一下(并做適當(dāng)?shù)难a(bǔ)充),目前web3.js 0.20.x 版本 已經(jīng)翻譯完成,歡迎大家前往查閱。 這里還幾個(gè)實(shí)用DEMO,供大家參考: 使用web3.js API在頁(yè)面中轉(zhuǎn)賬 web3.js 0....

    makeFoxPlay 評(píng)論0 收藏0
  • Web3與智能合約交互實(shí)戰(zhàn)

    摘要:本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接與智能合約交互實(shí)戰(zhàn)原文已更新,請(qǐng)讀者前往原文閱讀寫在前面在最初學(xué)習(xí)以太坊的時(shí)候,很多人都是自己創(chuàng)建以太坊節(jié)點(diǎn)后,使用與之交互。 本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接:Web3與智能合約交互實(shí)戰(zhàn)原文已更新,請(qǐng)讀者前往原文閱讀 寫在前面 在最初學(xué)習(xí)以太坊的時(shí)候,很多人都是自己創(chuàng)建以太坊節(jié)點(diǎn)后,使用geth與之交互。這種使用命令行交互的方法雖然讓很多程序員...

    liaoyg8023 評(píng)論0 收藏0
  • Geth控制臺(tái)使用及 Web3.js 使用實(shí)戰(zhàn)

    摘要:本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接控制臺(tái)使用及使用實(shí)戰(zhàn)原文已更新,請(qǐng)讀者前往原文閱讀在開發(fā)以太坊去中心化應(yīng)用,免不了和以太坊進(jìn)行交互,那就離不開。 本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接:Geth控制臺(tái)使用及 Web3.js 使用實(shí)戰(zhàn)原文已更新,請(qǐng)讀者前往原文閱讀 在開發(fā)以太坊去中心化應(yīng)用,免不了和以太坊進(jìn)行交互,那就離不開Web3。Geth 控制臺(tái)(REPL)實(shí)現(xiàn)了所有的web3 A...

    hlcc 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<