Me gustaría eliminar el dolor del infierno de devolución de llamada de desarrollo web3 y usar el patrón Promise y las palabras clave async/await tanto en el lado del cliente como en Node.js.
¿Existen compilaciones o bifurcaciones de web3.js que implementarían un patrón de promesa en lugar de un patrón de devolución de llamada? por ejemplo se podría decir
let result = await myfilter.get()
En vez de:
myfilter.get(function cb(error, res) {});
Web3 1.0 proporciona promesas además de devoluciones de llamada:
Para ayudar a web3 a integrarse en todo tipo de proyectos con diferentes estándares, proporcionamos múltiples formas de actuar en funciones asíncronas. La mayoría de los objetos web3.js permiten una devolución de llamada como último parámetro, además de devolver promesas a funciones de cadena.
https://web3js.readthedocs.io/en/v1.2.1/callbacks-promises-events.html
De hecho, debido a los 'promiEvents' de ethereum, puede usar promesas para desglosar las transacciones en cada paso de la transacción:
web3.eth.sendTransaction({from: '0x123...', data: '0x432...'})
.once('transactionHash', function(hash){ ... })
.once('receipt', function(receipt){ ... })
.on('confirmation', function(confNumber, receipt){ ... })
.on('error', function(error){ ... })
.then(function(receipt){
// will be fired once the receipt its mined
});
npm show web3 versions
entoncesnpm i install web3@1.0.0
Esto se puede lograr con un contenedor simple:
const promisify = (inner) =>
new Promise((resolve, reject) =>
inner((err, res) => {
if (err) { reject(err) }
resolve(res);
})
);
Para usarlo, simplemente envuelva sus llamadas web3 de la siguiente manera:
const accounts = await promisify(cb => web3.eth.getAccounts(cb));
Si desea prometer todos los métodos web3, puede usar un Proxy ES6:
// simple proxy to promisify the web3 api. It doesn't deal with edge cases like web3.eth.filter and contracts.
const proxiedWeb3Handler = {
// override getter
get: (target, name) => {
const inner = target[name];
if (inner instanceof Function) {
// Return a function with the callback already set.
return (...args) => promisify(cb => inner(...args, cb));
} else if (typeof inner === 'object') {
// wrap inner web3 stuff
return new Proxy(inner, proxiedWeb3Handler);
} else {
return inner;
}
},
};
const proxiedWeb3 = new Proxy(web3, proxiedWeb3Handler);
Y ahora usa web3 como una API prometida:
const accounts = await proxiedWeb3.eth.getAccounts();
await
como sugiere el autor. Mi consola dice que await can only be used with asyn functions
... no estoy seguro de por qué estaba ocurriendo ese error. En su lugar, creé un montón de "promesas" usando el envoltorio y lo vinculé a `Promise.all([p1,p2...]).then(function(results))... Esto funcionó para obtener múltiples async funciones para trabajar juntosSi desea tener promesas con contratos, eche un vistazo a Truffle Artifactor .
Para los métodos asincrónicos básicos de Web3, hice este Gist: https://gist.github.com/xavierlepretre/90f0feafccc07b267e44a87050b95caa
Pego aquí la versión al momento de escribir:
módulo.exportaciones = { prometer: función (web3) { // Canaliza los valores de una devolución de llamada de Web3. var callbackToResolve = función (resolver, rechazar) { función de retorno (error, valor) { si (error) { rechazar (error); } más { resolver (valor); } }; }; // Lista de funciones síncronas enmascaradas como valores. var syncGetters = { db: [], eth: [ "cuentas", "número de bloque", "coinbase", "precio del gas", "tasa de hash", "minería", "versión de protocolo", "sincronización"], net: [ "escuchando", "peerCount" ], personal: [ "listaCuentas" ], shh: [], versión: [ "ethereum", "red", "nodo", "susurro"] }; Object.keys(syncGetters).forEach(función(grupo) { Object.keys(web3[grupo]).forEach(función (método) { if (syncGetters[grupo].indexOf(método) > -1) { // Saltar } else if (tipo de web3[grupo][método] === "función") { web3[grupo][método + "Promesa"] = función () { var argumentos = argumentos; return new Promise(función (resolver, rechazar) { argumentos[argumentos.longitud] = callbackToResolve(resolver, rechazar); argumentos.longitud++; web3[grupo][método].apply(web3[grupo], args); }); }; } }); }); }, };
La función web3.eth.sendTransaction devuelve Promesa + Evento combinados.
Además, podemos usar devoluciones de llamada que corresponden a los eventos anteriores.
Para más información, ver:
//-------------------------------------
si usamos async/await con sendTransaction, devuelve un recibo . Pero sucederá solo cuando el recibo de la transacción esté listo. Esto puede tomar algo de tiempo.
Si deseamos obtener alguno de los resultados que proporcionan los eventos, podemos envolver la llamada de sendTransaction mediante una promesa personalizada.
Por ejemplo, podemos obtener la transacción Hash que regresa inmediatamente de esta manera:
function sendTransactionTxHashHelper(from: string, to: string, value: string) {
return new Promise((resolve, reject) => {
this.web3.eth.sendTransaction({
from: from,
to: to,
value: value,
}).on('transactionHash', (transactionHash) => {
resolve(transactionHash);
});
});
}
let transactionHash;
try {
transactionHash = await this.sendTransactionTxHashHelper(
'0x1234',
'0x5678',
'10000000'
);
} catch (e) {
console.log(`Error: ${e.name}:${e.message}`, e.stack);
}
console.log('transactionHash', transactionHash);
En realidad, es un parche bastante simple de escribir. Yo mismo escribí uno hace un tiempo, porque estaba cansado de lidiar con las devoluciones de llamadas. También permite que los envoltorios agradables hagan cosas como desbloquear una cuenta, hacer algunas cosas y luego bloquear la cuenta nuevamente, por ejemplo:
var readFile = Promise.denodeify(fs.readFile);
function whileUnlocked(web3, account, pwfile, task) {
return readFile(pwfile, 'utf8')
.then(function(pw) {
return web3.personal.unlockAccount(account, pw.trim())
.then(task)
.then(function() {
return web3.personal.lockAccount(account);
});
});
}
Ver: https://github.com/DeviateFish/web3.js/pull/1
Tenga en cuenta que escribí esto hace algún tiempo, y esta solución definitivamente podría mejorarse con funciones de idioma más nuevas, o sin usar la biblioteca de relleno polivalente de Promise que estoy usando (por ejemplo, aplicar versiones más nuevas de nodo), por lo que su kilometraje puede variar.
[E] Debo agregar que este enfoque no toca la API de filtros, ya que no es estrictamente compatible con el estilo Promise. Las promesas generalmente se refieren a cosas que se realizan de forma asincrónica una vez, no (potencialmente) varias veces. No estaba seguro de cómo abordar mejor esa discrepancia, así que los dejé solos.
Trevor Oakley
mikko ohtamaa
Trevor Oakley
mikko ohtamaa
Trevor Oakley
mikko ohtamaa
mikko ohtamaa
Trevor Oakley