Rx.Observable.repeat (indefinitely) with zip causes the browser to stop responding - rxjs

The following code causes the browser to stop responding, using a value like '100' for example for the repeat solves the problem, but in my case I don't have specific value for it.
Would you please suggest a solution:
var observer = Rx.Observer.create(function (x)
{
console.log(x);
},
function (err)
{
console.log('Error: ' + err);
},
function ()
{
console.log('Completed');
});
var repeat = Rx.Observable.repeat(10, null); //repeat indefinitely
var interval = Rx.Observable.interval(1000);
var zip = Rx.Observable.zip(repeat,
interval,
function(rep, inter)
{
return rep + inter;
});
zip.subscribe(observer);

The browser freezes because .repeat simply yields 10 indefinitely.
Since Rx is push-based, we have no way of knowing when zip needs another item. Instead, we just push new values to zip as they become available. The static (class-method?) repeat says "hey, I have new items RIGHT NOW ALWAYS HERE THEY ARE" and never relinquishes control-flow back to zip. This means zip never actually ends up subscribing to the interval observable, so zip just starts buffering indefinitely.
If you're coming from a functional background, then it would seem like an "infinite" list of "10"s would zip nicely with a finite list of anything. Which is absolutely true, assuming your infinite list is lazy. In this case, our "list" has a mind of it's own, and definitely isn't lazy.
I'd be happy to suggest a solution, but it seems that the example is contrived. What exactly are you attempting to do?

I was dealing with the same problem. Looks like delay can do the trick.
Here's the slightly modified version of your code:
var observer = Rx.Observer.create(function (x)
{
console.log(x);
},
function (err)
{
console.log('Error: ' + err);
},
function ()
{
console.log('Completed');
});
var repeat = Rx.Observable.of(10).delay(0).repeat(-1); //repeat indefinitely
var interval = Rx.Observable.interval(1000);
var zip = Rx.Observable.zip(repeat,
interval,
function(rep, inter)
{
return rep + inter;
});
zip.subscribe(observer);

Related

Protractor dealing with promises and arrays in flow control

I'm working on some Jasmine end-to-end testing, using Protractor test runner. The application I am testing is a simple webpage. I already have a test scenario that works fine.
Now I'd like to improve my code so that I can use the same script to run the testing scenario twice.
The first time: the test would be performed on the English version of the page
The second time: on a translated version of the same page.
Here is my code:
var RandomSentenceInThePage = ["Sentence in English", "Phrase en Francais"];
var i;
var signInButton;
var TranslationButton;
var RandomSentenceInThePageBis;
i = 0;
//Runs the testing scenario twice
while (i < 2) {
describe('TC1 - The registration Page', function() {
//the translation is done on the second iteration
if (i != 0) {
beforeEach(function() {
browser.ignoreSynchronization = true;
browser.get('https://Mywebsite.url.us/');
//we get the translation button then click on it
TranslationButton = element(by.css('.TranslationButtonClass'));
TranslationButton.click();
});
}
//On the first iteration, we run the test on the not translated pageā€¦
Else {
beforeEach(function() {
browser.ignoreSynchronization = true; //Necessary for the browser.get() method to work inside the it statements.
browser.get('https://Mywebsite.url.us/');
});
}
it('should display the log in page', function() {
//Accessing the browser is done in the before each section
signInButton = element(by.css('.SignInButtonClass'));
signInButton.click();
RandomSentenceInThePageBis = element(by.css('.mt-4.text-center.signin-header')).getText();
/*******************[HERE IS WHERE THE PROBLEM IS]*******************/
expect(RandomSentenceInThePageBis.getText()).toEqual(RandomSentenceInThePage[i]);
});
/*******************************************************************/
});
}
I have highlighted the problematic section. The code keeps running even before the comparison between RandomSentenceInThePage[i] and RandomSentenceInThePageBis are compared. And when they are finally compared, the loop is already done.
According to what I have seen on the other related topics, because of the use of expect statements and getText() methods, I am dealing with promises and I have to wait for them to be resolved. After trying for the whole day, I think I could use a hint on how to deal with this promise resolution. Let me know if you need more information.
Change while loop to for loop and declare the variable: i by let, rather than var
let can declare variable at code block scope like for, if block etc. But var can't.
Because protractor api execute async, thus when the expect()... execute for the second time. the value of i has become 2, not 1
for(let i=0;i<2;i++) {
describe('TC1 - The registration Page', function() {
....
})
}

RX: Synchronizing promises

Let's say I have a rather typical use of rx that does requests every time some change event comes in (I write this in the .NET style, but I'm really thinking of Javascript):
myChanges
.Throttle(200)
.Select(async data => {
await someLongRunningWriteRequest(data);
})
If the request takes longer than 200ms, there's a chance a new request begins before the old one is done - potentially even that the new request is completed first.
How to synchronize this?
Note that this has nothing to do with multithreading, and that's the only thing I could find information about when googling for "rx synchronization" or something similar.
You could use concatMap operator which will start working on the next item only after previous was completed.
Here is an example where events$ appear with the interval of 200ms and then processed successively with a different duration:
const { Observable } = Rx;
const fakeWriteRequest = data => {
console.log('started working on: ', data);
return Observable.of(data).delay(Math.random() * 2000);
}
const events$ = Observable.interval(200);
events$.take(10)
.concatMap(i => fakeWriteRequest(i))
.subscribe(e => console.log(e));
<script src="https://unpkg.com/rxjs/bundles/Rx.min.js"></script>

Implement repeat interval of more than a day for parse.com background job

I have created a background job like this:
Parse.Cloud.job("ResetLeaderboard",
function(request, response)
{
Parse.Cloud.useMasterKey();
var query = new Parse.Query("Leaderboard");
query.find(
{
success: function(results)
{
response.success("Success!");
},
error: function(error)
{
response.error(error);
}
})
.then(
function(results)
{
return Parse.Object.destroyAll(results);
});
});
I want to run this job every 15 days. But there is no option available at www.parse.com to set time interval for more than a day.
I think I need to use a time stamp and compare that value with current time. Can somebody show me the standard way to do this?
You're right that the job scheduling UI is constrained to a single day. The way to solve the problem is to have the job run daily, but to have it do nothing on 14 out of 15 runs. Those do-nothing runs will be wasteful, but microscopically so, and parse is paying the bills anyway.
The specifics of the solution depend on specific requirements. If you require maximum control, like exactly 15 days down to the millisecond, starting at a millisecond-specific time, you'd need to create some scratch space in the database where state (in particular, date) from the prior run is kept.
But the job looks like a cleanup task, where the requirement of "very nearly 15 days, beginning within 15 days" is sufficient. With that simpler requirement, your intuition is correct that simple date arithmetic will work.
Also, importantly, it looks to me like your intention is to find several objects in need of deletion, then delete them. The posted logic doesn't quite do that. I've repaired the logic error and cleaned up the promise handling as well...
// Schedule this to run daily using the web UI
Parse.Cloud.job("ResetLeaderboard", function(request, response) {
if (dayOfYear() % 15 === 0) {
var query = new Parse.Query("Leaderboard");
query.find().then(function(results) {
Parse.Cloud.useMasterKey();
return Parse.Object.destroyAll(results);
}).then(function() {
response.success("Success!");
}, function(error) {
response.error(error);
});
} else {
response.success("Successfully did nothing");
}
});
function dayOfYear() {
var now = new Date();
var start = new Date(now.getFullYear(), 0, 0);
var diff = now - start;
var oneDay = 1000 * 60 * 60 * 24;
return Math.floor(diff / oneDay);
}
The dayOfYear function is thanks to Alex Turpin, here

How to delete rows in Parse that satisfy some conditions?

Is there any way to effectively delete rows in Parse that do something like this SQL statement?
DELETE FROM table WHERE delete_me = 1
I've tried this, but it's very slow:
var query = new Parse.Query('table');
query.equalTo('delete_me', 1);
query.each(function(obj) {
return obj.destroy();
}).then(function() {
// Done
}, function(error) {
// Error
});
Almost there: find() will get the objects satisfying the delete criteria, then destroyAll() will destroy them all.
var query = new Parse.Query('table');
query.equalTo('delete_me', 1);
query.find().then(function(results) {
return Parse.Object.destroyAll(results);
}).then(function() {
// Done
}, function(error) {
// Error
});
Edit - to delete a table with more than 1k, it takes a little extra work with promises. The idea is to cursor through the table, grouping finds in batches of 1k (or some smaller increment), execute those finds concurrently using Promise.when(), then destroy the results concurrently the same way...
var query = new Parse.Query('table');
query.equalTo('delete_me', 1);
query.count().then(function(count) {
var finds = [];
for (var i=0; i<count; i+=1000) {
finds.push(findSkip(i));
}
return Parse.Promise.when(finds);
}).then(function() {
var destroys = [];
_.each(arguments, function(results) {
destroys.push(Parse.Object.destroyAll(results));
});
return Parse.Promise.when(destroys);
}).then(function() {
// Done
}, function(error) {
// Error
});
// return a promise to find 1k rows starting after the ith row
function findSkip(i) {
var query = new Parse.Query('table');
query.limit(1000);
query.equalTo('delete_me', 1);
query.skip(i);
return query.find();
}
Edit 2 - This might be faster, but you'd need to discover empirically:
// return a promise to delete 1k rows from table, promise is fulfilled with the count deleted
function deleteABunch() {
var query = new Parse.Query('table');
query.limit(1000);
query.equalTo('delete_me', 1);
query.find().then(function(results) {
return Parse.Object.destroyAll(results).then(function() {
return results.length;
});
});
}
function deleteAll() {
return deleteABunch().then(function(count) {
return (count)? deleteAll() : Parse.Promise.as();
});
}
The 1802 request thing is the rate-limit (30/sec). The next idea is to batch the work into smaller transaction-count promises and run them serially, keeping the rate low but stretching them out over time. That's the gist of my suggestion above in a couple of forms (before I understood that you have ~500k rows).
Unfortunately, parse enforces a 10sec timeout limit, too. I think about ~1k rows deleted per sec is achievable, but I fear your 500k table will not yield to any method on the free tier. I think you have only these alternatives:
(a) throttle on the client - use some form of setTimeout(), to perform small enough, short enough batches. (This is how my app handles it, because the heavy work is done only by admins, and I can instruct them to not reload a page.).
(b) deploy your own node server which basically implements idea (a), calling parse.com in small enough steps to keep it happy but places no computational burden on the client.
(c) a parse.com background job that wakes periodically and nibbles away at it. You only get one of these on the free tier, and I imagine most of the time it will just wake frequently and waste electricity.
(d) pay.
I'll be able to do some actual code/test late today. If I learn anything new I'll post here. Best of luck.

How to efficiently remove first element from a selection?

I have a page that displays some data using d3.js. Due to the heavy processing load, when the page load it freezes the browser for a few seconds.
I have determined that this "browser locking" behavior is due mostly to a line of the form:
selection.attr('d', linefn);
...where selection contains around 10K items.
I would like to replace this line with something like
function process_rest () {
if (selection.size() > 0) {
var next_item = first(selection); // function first() is hypothetical!
next_item.attr('d', linefn);
selection = rest(selection); // function rest() is hypothetical!
setTimeout(process_rest, 100);
return;
}
finish_up();
}
setTimeout(process_rest, 100);
I'm looking for an efficient way to implement either first and rest. My very naive guess would be something like:
function first(selection) {
return d3.select(selection[0][0]);
}
function rest(selection) {
selection[0] = selection[0].slice(1);
return selection;
}
...but, AFAIK, this is going "behind the API", or at least feels like it. Is there an "official" (i.e. documented) way to achieve the same result?
EDIT: deleted the shift variant (it's safer not to update selection until after the processing of the first element has been successfully completed).
You can simply use .each():
selection.each(function(d, i) {
setTimeout(function() { d3.select(this).attr("d", linefn); }, i * 100);
});

Resources