How do I consume and print a Promise result? - javascript

I'm trying to get the current block number from Binance Smart Chain (BSC).
In the documentation, provider.getBlockNumber() returns a Promise object.
Here are my attempts to consume and print the current block number into console.
I'm using Node.js v16.5.0 and Ethers.js 5.4.1.
var ethers = require("ethers");
var url = "wss://bsc-ws-node.nariox.org:443";
const provider = new ethers.providers.WebSocketProvider(url);
const blockNumber = async function() {
return await provider.getBlockNumber();
}
console.log(blockNumber());
process.exit();
This returns Promise { <pending> } on the console.
This block of code:
var ethers = require("ethers");
var url = "wss://bsc-ws-node.nariox.org:443";
const provider = new ethers.providers.WebSocketProvider(url);
async function blockNumber() {
const blockNumber = await provider.getBlockNumber();
return blockNumber();
}
blockNumber().then(data => {console.log(data)});
process.exit();
output exactly nothing in the console, almost as there's nothing wrong in the code.
Expected output should be a number, like 9380976.
Where did I go wrong?
EDIT 1: Added process.exit() because that's supposed to be in the original post.
ANSWER by #purple:
var ethers = require("ethers");
var url = "wss://bsc-ws-node.nariox.org:443";
const provider = new ethers.providers.WebSocketProvider(url);
async function blockNumber() {
const blockNumber = await provider.getBlockNumber();
return blockNumber;
}
blockNumber().then(data => {
console.log(data)
process.exit();
});
Result:
> node app
*pauses for a bit, then prints*
9397167
>

Did you mean return blockNumber; instead of return blockNumber();?

Related

Google Apps Script Hoisting and ReferenceError

I've been trying to find an answer to this for a few weeks, but couldn't quite do this, so I decided to ask.
I sometimes get this error:
ReferenceError: <SomeObject> is not defined
...whereas I know for sure that it is. The problem is that the object is located in a different file, so if I call the object from that file (or maybe even a third file), the code does work.
I believe this must have to do with how hoisting works, meaning I'm trying to call an object before it's declared.
But then how does it work exactly when you have different files?
Here's an example:
If I have the following code in one file and I run getID(), it works:
const SomeAPI = (function () {
const _auth = new WeakMap();
const _url = new WeakMap();
class SomeAPI {
constructor(url, user = DEFAULT_USER, pwd = DEFAULT_PWD) {
_url.set(this, url);
_auth.set(this, Utilities.base64Encode(`${user}:${pwd}`));
}
async fetch() {
const headers = {
Authorization: `Basic ${_auth.get(this)}`,
};
const options = {
headers,
};
const response = await UrlFetchApp.fetch(_url.get(this), options);
const data = JSON.parse(response);
return data;
}
}
return SomeAPI;
})();
const LIST_DATA = (async () => await getListData())();
async function getListData() {
const response = await new SomeAPI(ALL_SETTINGS['List API URL']).fetch();
return Array.isArray(response) ? response[0] : response;
}
const getID = async () => {
const listData = await LIST_DATA;
const listId = listData.list_id;
const id = {
sheetId: SpreadsheetApp.getActive().getId(),
listId
};
console.log(id);
return id;
};
However, if I move LIST_DATA, getListData() and getID() to a different file, I get:
ReferenceError: SomeAPI is not defined
Overall the project is composed of 17 different files.
All help is greatly appreciated!
Per the comment by #Cooper to your question, moving the file up works. I had the same problem with a class I created. I moved the file with the class to the top and it solved my problem.

UnhandledPromiseRejectWarning

const Web3 = require('web3');
const fs = require('fs')
const web3 = new Web3("http://localhost:7545");
const contract_address = "0x7484d32e891817702c5d7c764dBF7e592000b415";
async function web3Contract() {
const contract_abi = fs.readFileSync('./build/contracts/Bottle.json', 'utf8')
const Bottle = await new web3.eth.Contract(JSON.parse(contract_abi).abi, contract_address);
Bottle.methods.setName("Palm").send();
Bottle.methods.getGreeting().call();
}
async function run() {
try {
await web3Contract();
} catch (err) {
console.log('Your error is this - ' + err);
}
}
run();
I'm getting a error "UnhandledPromiseRejectWarning". I been googling this for hours and can't seem to fix this. Please guide me in the right direction. Thank you.
Pointer 1: Don't evaluate JSON.parse(contract_abi).abi as a parameter. If you do there is no way checking what it is - and it is possibly causing the error. Better:
const contract_abi = fs.readFileSync('./build/contracts/Bottle.json', 'utf8');
const abi = JSON.parse(contract_abi).abi;
console.log( abi); // do you get this far?
const Bottle = await new web3.eth.Contract(abi, contract_address);
Pointer 2: Don't log the string value of an error object when debugging - you will only get its toString() result which looks to be the same as logging error.message. Better:
console.log('Your error is this - ', err);
Supplying err as a second argument causes node to log additional properties of the error object including error.stack which provides trace information.

How to wait for the promise when using get in Firestore

I am just trying a simple get command with Firestore, using this code from Google it doesn't work because it's not waiting for the promise?
Earlier I had put only a snippet of code, this is the entirety of index.js -- I'm using Firestore with Dialogflow to build a Google Assistant app and trying to call a function from the welcome intent that gets a field from Firestore, then writes that field to a string (named question1), and then this string should be spoken by the assistant as part of the ssml response. I've been on this for at least 30 hours already, can't seem to comprehend promises in regards to intents, firestore, etc. I've tried about 10 different solutions, this one works, only it says "undefined" in other variations I have tried it would say undefined several times but after 2-3 passes the get command would be complete and then the variable would be read out. I'm just trying to figure out how to get the get command and variable set before moving onto the SSML response. Can anyone point me in the right direction?
'use strict';
const functions = require('firebase-functions'); //don't forget this one
// Import Admin SDK
var admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
var db = admin.firestore();
const collectionRef = db.collection('text');
const Firestore = require('#google-cloud/firestore');
var doc;
var question1;
const url = require('url');
const {
dialogflow,
Image,
Permission,
NewSurface,
} = require('actions-on-google');
const {ssml} = require('./util');
const config = functions.config();
const WELCOME_INTENT = 'Default Welcome Intent';
const app = dialogflow({debug: true});
async function dbaccess(rando) {
console.log("dbaseaccess started")
var currentquestion2 = 'question-' + rando.toString();
var cityRef
try { return cityRef = db.collection('text').doc(currentquestion2).get();
console.log("get command completed")
//do stuff
question1 = cityRef.data().n111
} catch(e) {
//error!
}
console.log("one line above return something");
return rando;
}
app.fallback((conv) => {
// intent contains the name of the intent
// you defined in the Intents area of Dialogflow
const intent = conv.intent;
switch (intent) {
case WELCOME_INTENT:
var rando = Math.floor(Math.random() * 3) + 1;
dbaccess(rando);
const ssml =
'<speak>' +
question1 +
'</speak>';
conv.ask(ssml);
break;
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
You have 2 options: you can use async/await or you can use Promise.then() depending on how you want the code to execute.
Async/await:
async function databasetest {
var cityRef;
try{
cityRef = await db.collection('cities').doc('SF');
// do stuff
} catch(e) {
// error!
}
Promise.then():
db.collection('cities').doc('SF').then((cityRef) => {
cityRef.get()
.then(doc => { /* do stuff */ })
.catch(err => { /* error! */ });
});
maybe a little of work around could help you, I'm not sure yet how you are trying to implement it.
function databasetest () {
var cityRef = db.collection('cities').doc('SF');
return cityRef.get()
}
// so you can implement it like
databasetest().then(doc => {
if (!doc.exists) {
console.log('No such document!');
} else {
console.log('Document data:', doc.data());
}
})
.catch(err => {
console.log('Error getting document', err);
});
More context would help to understand your use case better :)

Try statement never passes without throwing error

In the following block of code, I am trying to get user input and save them in a json file. If the the inserted item is already exists in the file it gets rejected. The issue here is that my programme always executes the catch clause and generate an empty array, although in some situations json file exists and it is ready to be read.
const fs = require('fs');
const loadFile = () => {
try{
const stringData = fs.readFileSync('note-data.json', 'utf8');
return [JSON.parse(stringData)];
} catch (e) {
return [];
}
};
const writeFile = (notes) => {
fs.writeFileSync('note-data.json', JSON.stringify(notes));
};
const addNote = (title, body) => {
let notes = loadFile();
const note = {
title,
body
}
console.log(notes);
const duplicateArray = notes.filter((note) => note.title === title);
console.log(duplicateArray);
if(duplicateArray.length === 0){
notes.push(note);
writeFile(notes);
}
};
The command line input is as follow:
node app.js add --title=Greeting --body="hello"
node app.js add --title=Greeting2 --body="hello2"
The output is:
[{"title":"Greeting","body":"hello"}]
The output should be:
[{"title":"Greeting","body":"hello"}, {"title":"Greeting2","body":"hello2"}]
My question is where this error occurs?
Typo?
fs.writeFileSync('note-date.json', JSON.stringify(notes));
Isn't the file 'note-data.json'?

async.each does not finish without error

I have a simple function to where I get the word count from an url. The script works if I have a low amount of urls. I only limit async 4 at a time. I watch my ram and cpu and it doesn't go near the max on my machine. Let's say after about 70ish urls there is no error. The script just sets there. I have it in a try catch block and it never catches. Any help would be appreciated.
I have tried lodash forEach instead of async and I get the same issue.
const async = require('async')
const wordcount = require('wordcount')
const afterLoad = require('after-load')
const htmlToText = require('html-to-text')
function getWordCount(urls, cb) {
async.eachLimit(urls, 4, function(url, cbe) {
try {
let html = afterLoad(url) // https://www.npmjs.com/package/after-load
let text = htmlToText.fromString(html)
let urlWordCount = wordcount(text) // https://www.npmjs.com/package/wordcount
console.log(url, urlWordCount)
cbe(null)
} catch(err) {
console.log(err)
urlWordCount = 0
console.log(url, urlWordCount, err)
cbe(null)
}
}, function(err) {
console.log("finished getting wordcount", err)
if (err) {
cb(err)
} else {
cb(null)
}
})
}
getWordCount(["https://stackoverflow.com/", "https://caolan.github.io/async/docs.html#eachLimit"], function(err){
console.log(err)
})
I think the issue is in the synchronous implementation of that after-load module, but it's indeed hard to judge unless you get an actual error (you could put some console.logs here and there on every line and see where your code actually gets stuck - or use a debugger for the same purpose).
What I'd propose though is to use proper asynchronous code - I run the example below with a set of 1000 urls and it did not get stuck - with usage of [scramjet] it's also more readable:
const {StringStream} = require('scramjet');
const wordcount = require('wordcount');
const fetch = require('node-fetch');
const htmlToText = require('html-to-text');
const {promisify} = require('util');
StringStream.fromArray(["https://stackoverflow.com/", "https://caolan.github.io/async/docs.html#eachLimit"])
.setOptions({maxParallel: 4})
.parse(async url => ({
url,
response: await fetch(url)
}))
.map(async ({url, response}) => {
const html = await response.text();
const text = htmlToText.fromString();
const count = wordcount(text);
return {
url,
count
};
})
.each(console.log)
;
I actually run this from a file with the URL's by changing the first lines to:
StringStream.from(fs.createReadStream('./urls-list.txt'), 'utf-8')
.lines()
.setOptions({maxParallel: 4})
// and so on.

Categories