Dart: wait for callback before continuing - callback

I was wondering whether it's possible to wait for a callback before continuing a process.
I'm using a library that handles a future internally and then if it was successful, does a callback, otherwise handles the error internally with no callback.
Now I'm trying to use this library to create an instance, then fill it with random test data and then update that entity.
Map generateRandomizedInstance() {
lib.createEntity((result1){
result1["a"] = generateRandomA();
result1["b"] = generateRandomB();
result1["c"] = generateRandomC();
...
lib.updateEntity(result1, (result2){
// want to return this result2
return result2;
})
});
}
This would be fine if I'm only creating one entity and updating it once, but I want to create lots of random data:
ButtonElement b = querySelector("button.create")..onClick.listen((e){
for (int i = 0; i < 500; i++) {
generateRandomizedInstance();
}
});
It doesn't take long for this code to crash spectacularly as the callbacks aren't coming back fast enough.
I've tried changing the method signature to
generateRandomizedInstance() async {
and then doing:
for (int i = 0; i < 500; i++) {
print(await generateRandomizedInstance());
}
but that await syntax seems to be invalid and I'm not completely sure how to wrap that callback code in some kind of future that I can wait for the callback to come back before continuing to the next iteration of the loop.
I've tried a while loop at the end of generateRandomizedInstance that waits for a result variable to not be null, but that kills the browser and seeing as I'm not always getting a callback, in some cases it could cause an infinite loop.
Any ideas / suggestion on how to pause that for loop while waiting for the callback?

This should do what you want:
Future<Map> generateRandomizedInstance() {
Completer<Map> c = new Completer<Map>();
lib.createEntity((result1){
result1["a"] = generateRandomA();
result1["b"] = generateRandomB();
result1["c"] = generateRandomC();
...
lib.updateEntity(result1, (result2){
// want to return this result2
c.complete(result2);
})
});
return c.future;
}
ButtonElement b = querySelector("button.create")..onClick.listen((e) async {
for (int i = 0; i < 500; i++) {
await generateRandomizedInstance();
}
});

Related

Javascript and Callback function

I’m a newbie in programming language and I’m learning Javascript. I’m trying to understand the concept of callback function. I realized that callback is intended a function passed as parameter, but when does it call?
In the below examples I used a classic approach to write functions and then I tried to use the arrow function. The callback is done() function, in the first example it is called after the parent function, in the second one after.
What is the reason? Can you give me an explanation? Thank you so much for the feedback
Example no. 1
function done(){
console.log("Done");
}
function increment(num, callBack){
for(var i = 0; i <= num; i++){
console.log(i);
}
return callBack();
}
increment(10, done);
Example no. 2
const done = () => {
console.log("Done");
}
const increment = (num, done) => {
for (var i = 0; i <= num; i++) {
console.log(i);
}
}
increment(10, done());
To use callback you need to specify that there'll be a callback function as a argument, and you need to call that somewhere in the parent function like this, and that's when it will be called:
function someFunction(callback){
//Do something if needed...
callback() //callback(someParameter) if you want to pass some parameter to the callback func
//Do something if needed...
}
In your 2nd example, it's actually not a proper way of using callback function because you did not call the callback function inside parent function. You can modify it to to make it work as 1st example like this:
const increment = (num, done) => {
for (var i = 0; i <= num; i++) {
console.log(i);
}
done(); //call the callback function
}
increment(10, done); //just pass the name of callback func, not call it like you did "done()"

SAPUI5 Using promises to wait for code execution

I'm in a loop here and for each iteration I'm calling _checkExistingDefaultTimes to check if a record exists.
The problem is, the code in the loop is not executed until I'm outside the for loop.
Is there any way I can use a Promise so that it forces the .then code (pushing oOpeningTimes) before the loop finishes?
var oOpeningTimes = [];
for (var i = 0; i < numberOfDays; i++) {
this._checkExistingDefaultTimes(test.SiteInfo.SiteId,test.EffectiveDateFrom,
test.EffectiveDateTo)
.then(function (bResult) {
oOpeningTimes.push({
temporaryDate: oDate,
startTime1: oModelData[oWeekday].startTime1,
endTime1: oModelData[oWeekday].endTime1,
});
});
oStoreData.OpeningTimes = oOpeningTimes;
oModel.setData(oStoreData);
After the loop, no. The for-loop is a synchronous construct and the promise is async. What you need to do is wait until all of the promises generated in the loop are resolved before running your follow-on code. This is what Promise.all is for. You could do something like the following:
var oOpeningTimes = [];
var oPromises = [];
for (var i = 0; i < numberOfDays; i++) {
oPromises.push(this._checkExistingDefaultTimes(test.SiteInfo.SiteId,test.EffectiveDateFrom,
test.EffectiveDateTo)
.then(function (bResult) {
oOpeningTimes.push({
temporaryDate: oDate,
startTime1: oModelData[oWeekday].startTime1,
endTime1: oModelData[oWeekday].endTime1,
});
}));
Promise.all(oPromises).then(function() {
oStoreData.OpeningTimes = oOpeningTimes;
oModel.setData(oStoreData);
})

How to do simple javascript looping in protractor

for ( i = 0; i < 100; i++) {
browser.manage().logs().get('browser').then(function(browserLog) {
console.log(i);
});
}
I am trying to run this using protractor, but i get hundred times 100 printed in console. I have some functionality which am trying to implement using looping.How can i do looping in protractor?
This is because the functions you're passing to then all close over the variable i, not the value that variable has when you create the functions. So later, when the functions are called, they all see the value of i as it is then, after the loop is complete (100).
If you want to capture the value of i as it is when you create the function, you can use ES5's Function#bind:
for ( i = 0; i < 100; i++) {
browser.manage().logs().get('browser').then(function(index, browserLog) {
console.log(index);
}.bind(null, i));
}
bind returns a new function that, when called, will call the original function with a given this value (in this case I'm using null) and any arguments you follow that with, followed by arguments given to the function bind returned.
Another approach is a builder function:
for ( i = 0; i < 100; i++) {
browser.manage().logs().get('browser').then(buildHandler(i));
}
function buildHandler(index) {
return function(browserLog) {
console.log(index);
};
}
That has the advantage of allowing the caller to control this.

How do I DumpLive results of a long running process?

I've tried Observable.Create
waits to finish before showing any results.
Possibly because the example I'm trying to follow is a changing live value, not a changing live collection.
and
ObservableCollection<FileAnalysisResult> fileAnalysisResults = new ObservableCollection<FileAnalysisResult>();
I can't seem to apply because .DumpLive() isn't applicable to an ObservableCollection.
Short answer: use LINQPad's DumpContainer:
var dc = new DumpContainer().Dump();
for (int i = 0; i < 100; i++)
{
dc.Content = i;
Thread.Sleep(100);
}
Long answer: DumpContainer writes to LINQPad's standard HTML results window, so you can see the value change in place while the main thread is blocked, whereas calling DumpLive on an IObservable uses a WPF control to render the updates, so the main thread must remain unblocked in order to see updates as they occur.
It's also possible to dump a WPF or Windows Forms control and update it in place:
var txt = new TextBox().Dump();
for (int i = 0; i < 100; i++)
{
txt.Text = i.ToString();
await Task.Delay(100);
}
Just as with DumpLive, you must be careful not to block the main thread. If you replaced await Task.Delay with Thread.Sleep, you'd block the UI thread and nothing would appear until the end.

Callback functions that reference each other? Nested if statements? Need guidance

first time long time here.
I just started programming in javascript recently, I'm running into a question of design.
I have some working code that:
1. Waits for specific input from the serial port,
2. When input is found it moves to the next function.
3. The next function sends a command(s) over the serial port and then waits for input again.
Now I have 9 functions defined as stepone() steptwo() etc.... There has to be a better way to do this. Each function is the same except with different variables for input and output desired.
However, I do not want the program to skip steps. It needs to wait for the correct serial input before sending the next command.
I've tried using callback functions referencing each other, it just seems...wrong?
Also, it doesn't work. It doesn't wait for the right input before sending commands.
var waitforinput = function(input, regex, callback)
{
if (regex.search != -1)
callback();
};
var sendcommand = function(command,callback)
{
port.writeline(command);
if (callback)
callback();
};
var connect = function()
{
var int = setInterval(function()
{
waitforinput(input, "Please choose:", function()
{
sendcommand("1", function()
{
waitforinput(input, "You choosed", function()
{
sendcommand("saveenv 1");
});
});
});
},50);
};
I ended up using switch() with cases and keeping track of a variable called step:
step = 1;
switch(step)
{
case 1:
if (inputbuffer.search('Please choose') !== -1)
{
if (!waitdisplaystarted)
{
waitdisplaystarted = true;
waitint = setInterval(showwait,1000);
}
window.$("#instructions").hide();
window.$("#status").html("Step 1: Choosing boot option.");
SELF.sendserialcommand("1");
step = 2;
}
break;
case 2:
if (inputbuffer.search('You choosed 1') !== -1)
{
SELF.sendserialcommand('setenv bootargs "board=ALFA console=ttyATH0,115200 rootfstype=squashfs,jffs2 noinitrd"\r');
setTimeout(function(){SELF.sendserialcommand('saveenv\r');}, 50);
window.$("#status").html("Step 2: Transferring new kernel.");
setTimeout(function(){SELF.sendserialcommand('tftp 0x80600000 kernel.bin\r');}, 2000);
step = 3;
}
break;
case 3:
if (inputbuffer.search('Bytes transferred = ' + 878938) !== -1)
{
window.$("#status").html("Step 3: Erasing old kernel.");
SELF.sendserialcommand('erase 0x9f650000 +0x190000\r');
step = 'finished';
}
}