I am using truffle deployer to deploy my solidity contracts:
module.exports = function(deployer, network) {
...
}
I would like to store some data on the chain within this migration process. Basic storing of data is working properly by using the promise callback parameter and call some functions on the contract. But I need to do something more complex like explained in the following code snippet:
deployer.deploy(A).then(instance => {
instance.addB(id, some params ...).then(result => {
// result is not the added B -> using getB() to load B
instance.getB(id).then(instanceB => {
instanceB.addC(id, some params ...);
})
});
})
The problem is, that the inner functions are not executed properly. instance.addB() does properly store B into the chain. But C is never stored to the chain and I don't get why.
Also if I add console.log('some text') to the inner function it's not printed to the console.
Does someone know how to resolve this issue?
Use "await/async" instead of the promise callbacks.
Related
I am using node-mssql to perform a bunch of operations inside a transaction. Spcifically, the methods used in order are begin tran,bulk,bulk,exec,commit. Here is part of the code, which works as-is:
// bulk insert #columns
.then(result => {
const request=new sql.Request(globalTx);
const tableObj = new sql.Table('#columns'); //#columns
/* some code to build the desired tableObj*/
return request.bulk(tableObj);
})
// exec proc
.then(result => {
returnObject.lastSuccessfulStep='bulk #data'
returnObject["#columns rows"]=result.rowsAffected
const request=new sql.Request(globalTx);
/* some code to build the desired proc call*/
return request.execute('spc_sqlDMLCommand');
})
//commit
.then(result => {
return globalTx.commit(); // returns promise
})
So you can see the use of chained .thens. There is a catch() at the end.
My problem is that in the case od the execute method, while the then() /catch() promise structure feels friendly to me, I also need the information that the method returns through its callback. Citing the reference about the second parameter:
callback(err, recordsets, returnValue) - A callback which is called
after execution has completed, or an error has occurred. returnValue
is also accessible as property of recordsets. Optional. If omitted,
returns Promise.
Is there a way to save err/recordsets/returnValue to some objects while still maintaining the flow, ie not having to cut-paste the subsequent then()s into the execute's callback?
Solution attempt:
I tried using a callback:
request.execute('spc_sqlDMLCommand',function cb(a,b,c){
console.log('a:\n',a,'b:\n',b,'c:\n',c)
});
but I got this error:
message: 'Requests can only be made in the LoggedIn state, not the
SentClientRequest state', code: 'EINVALIDSTATE'
Following this up on the internet, it seems to be about multiple queries having problems. But, it already works for me if I do it in the way mentioned above...
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 3 years ago.
I have some code that authenticates by posting an object using npm request.
After posting the JSON object, a JSON response is returned which contains an authn token I can use in future GET/POST request headers.
I have some async code that returns the correct authn token but I can only access it via the .then function code block.
I have read through the usual linked thread here: How do I return the response from an asynchronous call? but even though the return result is in the .then function I still get undefined when trying to do anything other than console.log().
const postData = {
"auth": {
"username": "username",
"password":"password"
}
};
var returnRequest = () => {
var options = {
method: 'POST',
url: 'https://api.appnexus.com/auth',
body: postData,
json: true
};
return new Promise(async (resolve, reject) => {
await requestAPI(options, function (error, response, body) {
if (error) {
reject(error);
}
resolve(body);
});
})
}
var returnedResult
returnRequest()
.then((result) => {
returnedResult = result.response.token
})
.catch((error) => {
console.log(error);
})
console.log(returnedResult)
I would expect to see the returnedResult store the token as I understand it, the .then promise only runs one the request has happened?
A developer said I have to build all subsequent code inside the .then block but that sounds crazy, that I have to have my whole program inside this returnRequest function rather than be able to pass the returned token back outside to a global variable?
Is that the correct way to do it, and am I supposed to just build all subsequent requests using the result.response.token inside the
returnRequest()
.then((result) => {
returnedResult = result.response.token
})
function?
.then is the mechanism that promises use to let you know when the value is available. The "when" part is important: only the promise object knows what time your code should run at. So even if you try to write some extra code to store values in variables, the question of when it's safe to try to get those variables can only be answered by the promise's .then method.
So yes, any code that needs the values to be available needs to be put in the .then of the promise. Maybe you have some separate part of the codebase that needs to interact with the result, and so it feels clumsy to try to have to copy that code over to here. Well you don't need to: you just need to pass that other code the promise, and then that other code can call .then on the promise itself. For example:
const tokenPromise = returnRequest()
.then(result => result.response.token);
// Anywhere else that tokenPromise in scope can write whatever code it needs to:
tokenPromise.then(token => {
// Do anything with the token
});
// And a completely different piece of code can write its own stuff with the token
tokenPromise.then(token => {
// Do other stuff with the token
});
No you don't need to use result.response.token everywhere to use the authn token.
The thing here to understand is the flow of code. Your console.log statement may be returning you undefined .
Why ? Haven't you updated the global variable inside the then block of promise ?
Yes you have ! But the problem is that it is not reflected to you in the console log statement because this very statement is executed before any updation in the global variable.
So, it gets updated but it takes time to do so.
This is what is known as asynchronous code .
Now what about the suggestion of wrapping the code inside the .then block.
If you will add a console log statement beneath the updation (inside the then block) it will print you the exact token you are looking for.
But actually you don't need that , you can use aysnc/ await syntax to make it look like synchronus code, and then it will don't confuse you.
For example you can do something like this.
let result = await returnRequest();
let returnedToken =result.response.token;
// Now it will print you the token
console.log(returnedToken)
Make sure to add the async keyword infront of the function using await.
there are several ways to do what you ask, one way would be to wrap your entire code in async iife (immediately invoked function expression) so that you can use await.
!async function(){
....
....
....
var returnedResult = await returnRequest()
.then((result) => {
return result.response.token;
})
.catch((error) => {
console.log(error);
})
//continue
}()
I’ll try and answer parts of this question.
The setting of value for global variable inside of the .then callback is correct and you’ll have the value inside the “then” block. You can console.log inside of it and check.
The console.log outside in the “global” scope runs even before the the promise is resolved. Remember that java script is even driven. It registers the api call and continues executing the next line of it can. Which is why you’ll see an undefined value of token.
If all your subsequent requests depend on the auth token and you need to call some other API in the same call, you’ll have to do it in the .then call or create a promise chain with multiple .then which is essentially the main benefit of Promises. Previous result is passed on to the next promise.
I am designing an Automation Framework using Protractor-cucumber for my company. Libraries used in this framework are as below:
Protractor
Cucumber-js
Gulp
Chai
Chai-as-promised
Suporting Libraries
1. Protractor-cucumber-framework
My function library has all the re-usable UI Interaction functions which are to be called in cucumber step definitions.
There is a function which iterates through a web-table, fetches values and pushes the same into an array as below.
fetchTableContentsToArray:async function(Page,ORString){
let tableArray = []; //Blank array to store table data
await element.all(by.css(##LOCATOR##)).each(async function(element){
await element.getText().then(async function(value){
await tableArray.push(value);
});
}).then(async function(){
console.log(tableArray);
return await tableArray;
});
},
I have required the file having this function within the step definition file and i am able to call this function. but on doing so the console.log() statement inside the function prints the array into the console however upon calling this function into a step definition file, the console prints undefined. Not sure why the function would return undefined instead of an array.
//Step definition of the cucumber step
let driver = require('Path to functions file');
Then(/^I check for new data on "([^"]*)" on "([^"]*)"$/,async function (element, page) {
await driver.fetchTableContentsToArray(page,element).then(async function(val){
console.log(val);
})
Output:
["test1",
"test2"
"test3"
"test4"] // this is printed by console.log() inside the function
undefined //
I have also tried doing below in cucumber step definition but nothing helps. Instead it prints Promise { } and on resolving the promise, it prints undefined.
Then(/^I check for new data on "([^"]*)" on "([^"]*)"$/,async function (element, page) {
await driver.fetchTableContentsToArray(page,element).then(async function(val){
console.log(val);
})
I have tried all combinations but still not quiet able to figure out what the issue could be.
Any help or rectification is welcome. Thanks in advance.
function call from step definitions file should print the returned array/Object upon promise resolution.enter code here
fetchTableContentsToArray: function(Page,ORString){
return element.all(by.css(##LOCATOR##)).getText();
// because getText() return a promise, unnecessary to use async/await
}
Then(/^I check for new data on "([^"]*)" on "([^"]*)"$/,async function (ele, page) {
let val = await driver.fetchTableContentsToArray(page,ele);
console.log(val);
return val;
})
You are using Async/Await but then you are still working with the .then() callbackfunction. Maybe this is the Problem.
With Async/Await you can work like this:
async function() {
const val = await someFunctionWithPromise()
console.log(val)
}
Instead of:
function() {
someFunctionWithPromise().then(funtion(val) {
console.log(val)
})
}
There is similar framework based on technologies you listed, try to look inside github repository maybe you get a clue :)
https://thesoftwarehouse.github.io/Kakunin/docs/index.html
I'm trying to achieve something similar to the methods you get with the core fs module where you have an Async method by default and a Sync method if requested such as fs.readDir() and fs.readDirSync();
I have a method called fetchUrls that fetches files from a list of urls and returns a promise. I want to add another method called fetchUrlsSync which calls fetchUrls and blocks the thread until the promise is resolved. how can that be done?
sample code:
fetchUrls(startDate, endDate) {
return new Promise((resolve, reject)=> {
// some async work...
})
}
fetchUrlsSync() {
// call fetchUrls and block until resolved
}
those two functions are methods on a class.
This isn't possible directly in node.js. It also goes against the general model in node, which is to perform all IO asynchronously.
It is however possible to use a compiled Node.js extension to achieve this called http-sync.
I have a promise that returns data and I want to save that in variables. Is this impossible in JavaScript because of the async nature and do I need to use onResolve as a callback?
Can I somehow use this (e.g. wrap it with async/await):
const { foo, bar } = Promise.then(result => result.data, errorHandler);
// rest of script
instead of this?
Promise.then(result => {
const { foo, bar } = result.data;
// rest of script
}, errorHandler);
Note: Bluebird library is used instead of native implementation, and I can't change from Promise to asnyc/await or Generators.
NO you can't get the data synchronously out of a promise like you suggest in your example. The data must be used within a callback function. Alternatively in functional programming style the promise data could be map()ed over.
If your are OK using async/await (you should it's awesome) then you can write code that looks synchronous yet retain the asynchronicity of a promise (see #loganfsmyth comments).
const { foo, bar } = await iAmAPromise.then(result => result.data);
Overall since you are already using ES6 I assume you are also using a transpiler. In which case you should definitely give async/await a try.
Just be sure to weight in the decision that as today they are not yet a ratified specification.
While you can get a value from an awaited Promise inside an async function (simply because it pauses the function to await a result), you can't ever get a value directly "out" of a Promise and back into the same scope as the code that created the Promise itself.
That's because "out of" would mean trying to take something that exists in the future (the eventually resolved value) and putting it into a context (synchronous variable assignment) that already happened in the past.
That is, time-travel. And even if time-travel were possible, it probably wouldn't be a good coding practice because time travel can be very confusing.:)
In general, if you find yourself feeling like you need to do this, it's good sign that you need to refactor something. Note that what you're doing with "result => result.data" here:
Promise.then(result => result.data, errorHandler);
// rest of script
..is already a case of you working with (literally, mapping over) the value by passing it to a function. But, assuming that "// rest of script" does something important related to this value, you probably want to continue mapping over the now updated value with yet another function that then does something side-effect-y with the value (like display the data on the screen).
Promise
.then(({ data }) => data)
.then(data => doSomethingWithData(data))// rest of script
.catch(errorHandler);
"doSomethingWithData" will be called (if it's ever called) at some unknown point in the future. Which is why it's a good practice to clearly encapsulate all that behavior into a specific function and then hook that function up to the Promise chain.
It's honestly better this way, because it requires you to clearly declare a particular sequence of events that will happen, explicitly separated out from the first run through all of your application code's execution.
To put it another way, imagine this scenario, hypothetically executed in the global, top-level scope:
const { foo, bar } = Promise.then(result => result.data, errorHandler);
console.log(foo);
//...more program
What would you expect to happen there? There are two possibilities, and both of them are bad.
Your entire program would have to halt and wait for the Promise to execute
before it could know what "foo" & "bar" would... nay, might be. (this is
what "await," inside an async function, does in fact do: it pauses
the entire function execution until the value is available or an the error is thrown)
foo and bar would just be undefined (this is what actually
happens), since, as executed synchronously, they'd just be
non-existent properties of the top-level Promise object (which is not itself a "value,"
but rather a quasi-Monadic wrapper around getting an eventual value OR an error) which most
likely doesn't even contain a value yet.
let out; mypromise.then(x => out = x); console.log(out)
Only use this code when
you are debugging by hand,
and you know the promise has already succeeded
Behaviour of this code:
While the promise has not resolved yet, out will be undefined.
Once the promise resolves to a failure, an error is thrown.
When the promise resolves to success, (which may be after the console.log), the value of out will change from undefined to the Promise result — maybe in the middle of what you were doing.
In production code, or really any code that runs without you, the code that uses the Promise result should be inside the .then() callback, and not use some out variable. That way:
your code won't be run too early (when the result is still undefined),
and won't run too late (because you don't need 'I think sleeping for 10 seconds should do it' workarounds),
and won't erroneously run when the promise fails.
I have a solution of getting this value "out" if you will. This is a method at backend for uploading multiple files to AWS S3 which must be dealt asynchronously. I also need the responses from S3, so I need the values out of the Promise:
async function uploadMultipleFiles(files) {
const promises = []; //Creating an array to store promises
for (i = 0; i < files.length; i++) {
const fileStream = fs.createReadStream(files[i].path)
const uploadParams = {
Bucket: bucketName,
Body: fileStream,
Key: files[i].filename
}
promises.push(s3.upload(uploadParams).promise()) //pushing each promise instead
//of awaiting, to enable for concurrent uploads.
}
await Promise.all(promises).then(values => {
console.log("values: ", values) //just checking values
result = values; //storing in a different variable
});
return result; //returning that variable
}
The key lines in context with the issue being discussed here are these :
await Promise.all(promises).then(values => {
console.log("values: ", values) //just checking values
res = values; //storing in a different variable
});
return res; //returning that variable
But of course we have to also await in the function that will be calling this :
const result = await uploadMultipleFiles(files);
All you need to do is to extract all you have in your promise by using a .then
yourFunction().then( resp => {
... do what you require here
let var1 = resp.var1;
let var2 = resp.var2;
...
.....
})
yourFunction() should return a Promise
How to Get A Value From A Promise
YES! You can extract value out of a promise!
Do NOT let anyone here say you cannot. Just realize any variable that stores your returned promise value will likely have a short delay. So if you have a JavaScript script page that needs that data outside of the Promise or async-await functions, you may have to create loops, interval timers, or event listeners to wait to grab the value after some time. Because most async-await-promises are REST calls and very fast, that wait would require just a quick while loop!
It is easy! Just set a variable (or create a function) that can access the value inside your async or promise code and store the value in an outside variable, object, array, etc you can check on. Here is a primitive example:
// I just created a simple global variable to store my promise message.
var myDelayedData = '';
// This function is only used to go get data.
// Note I set the delay for 5 seconds below so you can test the delay
const getData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('my promise data'), 5000);
});
}
// I like to create a second async function to get the data
// from the promise object and save the data to my global variable.
const processData = async () => {
let data = await getData();
// Save the delayed data to my global variable
myDelayedData = data;
}
// Start the data call from the promise.
processData();
// Open up your browser, hit F12 to pull up the browser devtools
// Click the "console" tab and watch the script print out
// the value of the variable with empty message until after
// 5 seconds the variable is assigned to the resolved promise
// and apears in the message!
// THAT IS IT! Your variable is assigned the promise value
// after the delay I set above!
// TEST: But let's test it and see...
var end = setInterval(function(){
console.log("My Result: " + myDelayedData);
if(myDelayedData !== ''){
clearInterval(end);
}
}, 1000);
// You should see this in devtools console.
// Each line below represents a 1 second delay.
My Result:
My Result:
My Result:
My Result: my promise data
Most people seeing this code will say "Then why use a Promise, just make a call for the data, pause, and update your application?" True: The whole point of a Promise is to encapsulate data processes inside the promise and take actions while the rest of the script continues.
But... you may need to output a result outside the Promise. You may have other global processes that need that data because it changes the state of the global application, for example. But at least you know you can get to that Promise data if you needed it.