Is there a methodology to test (potential) interleaving of asynchronous functions with vows?
For example:
// Topic portion
var user = new User('jacob')
user.set('email,'foo#bar.com')
user.save() // a
user.set('email',derp#cherp.com')
user.save() // b
user.refresh(this.callback) // Reload from database
// Callback
assert.equals(user.email,'derp#cherp.com')
There is could be a race condition between the two saves. When writing my tests I want to ensure that my API is ensuring that b finishes last (and that we have the correct final value for the email). With the way that's it written, the test will pass coincidentally some of the time.
Heres the example from the vows docs:
The nested contexts act as nested callbacks and pass the return arguments to the next context.
Docs: http://vowsjs.org/
{ topic: function () {
fs.stat('~/FILE', this.callback);
},
'after a successful `fs.stat`': {
topic: function (stat) {
fs.open('~/FILE', "r", stat.mode, this.callback);
},
'after a successful `fs.open`': {
topic: function (fd, stat) {
fs.read(fd, stat.size, 0, "utf8", this.callback);
},
'we can `fs.read` to get the file contents': function (data) {
assert.isString (data);
}
}
}
}
Related
I'm new to using Express.js. I'm working on my first endpoint which is to create a user. To accomplish this, it first has to be checked whether the username or email address already exists. After some research on how to do this, here's the code I've come up with:
// Check whether the user_name or email already exists
pool.query('SELECT CASE WHEN EXISTS (SELECT * FROM users WHERE user_name = $1 OR email = $2) THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END', [values.user_name, values.email], (error, results) => {
if (error) {
throw error
}
if (results.rows[0].case === '1') {
console.log('User exists so send message to this effect back to client');
} else {
console.log('User does not exist so we can call INSERT query');
pool.query('INSERT INTO users (first_name, last_name, user_name, email, password, last_password, password_salt) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *', [values.first_name, values.last_name, values.user_name, values.email, values.password, values.password, 'tmp_salt'], (error, results) => {
if (error) {
console.error('Something went wrong');
throw error;
}
console.log('Results from INSERT:', results);
res.status(201).send(`User added with user_id: ${results.rows[0].user_id}`);
});
}
});
It's obviously not finished yet but I'm curious if this nested approach I've used is the best way to do it? In other words, first I'm checking for the existence of user_name and/or email and only if both don't exist am I performing the INSERT.
What do you think?
There are really two different questions there:
Is checking then inserting the right approach?
Is nesting the right approach?
Is checking then inserting the right approach?
Not usually, no, it leaves you open to a race condition:
Client A sends joe#example.com / funkypassword
Client B sends joe#example.com / somethingelse
The main thread picks up the task for Client A's request and starts the asynchronous check to see if the user exists
While waiting for that asynchronous result, the main thread picks up Client B's request and starts the asynchronous check to see if the user exists
Both checks come back clear (no user exists)
The main thread inserts one of those sets of details (Client A's or Client B's)
The main thread tries to insert the other one of those sets of details (Client B's or Client A's)
At this point, if the database is set up correctly, you'll get an insertion error (primary or unique key violation).
Instead, you ensure the DB is set up that way and expect to get an error if the user already exists, and don't do the check at all. Just do the insert, and look at the error if you get one to see if it's a primary or unique key constraint violation.
Is nesting the right approach?
This particular task may not need multiple DB operations (see above), but many others will. So is nesting the right way to handle that?
It's certainly been the main way to handle it for a long time, but it has the issue of quickly becoming "callback hell" where you have lots of nested operations, each in its own callback to a previous operation, etc., etc. It can get very hard to manage. But you can do it that way if you like, and many have done for some time.
The more modern alternative is to use promises and async/await. In an async function, you can make the function wait for an asynchronous process to complete before continuing with its logic. That way, your logic isn't buried in callbacks.
Suppose you have to do two or three database operations, where whether it's two or three depends on the first operation's result, and where information from earlier calls is needed by later ones. With nesting, you might do something like this:
pool.query("DO THE FIRST THING", (error1, results1) => {
if (error1) {
/*...handle/report error...*/
return;
}
const thirdThing = (results2) => {
pool.query("DO THE THIRD THING with results1 and results2 (which may be null)", (error3, results3) => {
if (error3) {
/*...handle/report error...*/
return;
}
/*...finish your work using `results1`, `results2`, and `results3`...*/
});
};
if (/*results1 says we should do the second thing*/) {
pool.query("DO THE SECOND THING with results1", (error2, results2) => {
if (error2) {
/*...handle/report error...*/
return;
}
thirdThing(results2);
});
} else {
thirdThing(null);
}
});
You might isolate the three operations as functions, but while that's good for reuse if it's relevant and possibly for debugging, it doesn't help much with the callback hell:
function firstThing(callback) {
pool.query("DO THE FIRST THING", callback);
}
function secondThing(paramA, callback) {
pool.query("DO THE SECOND THING with paramA", callback);
}
function thirdThing(paramA, paramB, callback) {
pool.query("DO THE THIRD THING with paramA and paramB (which may be null)", callback);
}
// ...and then where your code was:
const done = (error, results1, results2, results3) => {
if (error) {
/*...handle/report error...*/
} else {
/*...do your final work here using `results1`, `results2` (which may be `null`), and `results3`...*/
}
});
firstThing((error1, results1) => {
if (error1) {
done(error1);
} else if (/*results1 says we should do the second thing*/) {
secondThing(results1, (error2, results2) => {
if (error2) {
done(error2);
} else {
thirdThing(results1, results2, (error3, results3) => {
done(error3, results1, results2, results3);
});
}
});
} else {
thirdThing(results1, null, (error3, results3) => {
done(error3, results1, null, results3);
});
}
});
But suppose we had a poolQuery function that put a promise wrapper around pool.query. Here's how that could look:
async function firstThing() {
return await poolQuery("DO THE FIRST THING");
}
async function secondThing(paramA) {
return await poolQuery("DO THE SECOND THING with paramA");
}
async function thirdThing(paramA, paramB) {
return await poolQuery("DO THE THIRD THING with paramA and paramB (which may be null)");
}
// ...and then where your code was, making it an `async` function:
try {
const results1 = await firstThing();
const results2 = (/*results1 says we should do the second thing*/)
? await secondThing(results2)
: null;
const results3 = await thirdThing(results1, results2);
/*...do your final work here using `results1`, `results2` (which may be `null`), and `results3`...*/
} catch (error) {
/*...handle/report error...*/
}
Or if you aren't going to reuse those queries, then:
try {
const results1 = await poolQuery("DO THE FIRST THING");
const results2 = (/*results1 says we should do the second thing*/)
? await poolQuery("DO THE SECOND THING with results1")
: null;
const results3 = await poolQuery("DO THE THIRD THING with results1 and results2 (which may be null)");
/*...do your final work here using `results1`, `results2` (which may be `null`), and `results3`...*/
} catch (error) {
/*...handle/report error...*/
}
How simple and clear is that? :-) It gets even more powerful when you have loops and such involved.
Suppose we have an observable main object array, and observable data about that array (e.g. suppose we have selectedReports and reportParameters) . Now suppose we emit action to either add report to the array or remove report from that array. How do we run an action to fetch the data for reportParameters, as reaction?
Thus far, my attempt, which isn't working, looks like this:
// report parameters stuff
async fetchAllReportParameters() {
reaction(
() => this.selectedReports,
async (reports) => {
// reset the report parameters
this.reportParameters = {}
// fetch the parameters for all the reports
await reports
.forEach((report) => {
this.fetchReportParameters(report.Id)
})
}
)
}
/**
* fetches report parameters for a reportId
* #param {number} reportId
*/
fetchReportParameters = (reportId) => {
this.reportParameters[reportId] = []
const onSuccess = (reportParameters) => {
this.reportParameters[reportId] = reportParameters
}
this.api.GetReportParameters(reportId)
.then(onSuccess, this.fetchReportParametersError)
}
fetchReportParametersError = (error) => {
// TODO: output some error here
}
Are you ever actually calling fetchAllReportParameters? If you don't, the reaction will never be created. You may instead like to create the reaction from the constructor, assuming you always want it to be run. One example:
class SomeStore {
constructor() {
this.disposeReportsReaction = reaction(
() => this.selectedReports.slice(),
reports => {
// ...
}
)
}
}
Call storeInstanceName.disposeReaction() whenever you're done with the reaction.
Notice that I've used .slice() here. This is because if you simply pass the array reference, the reaction will never be called. See reaction docs: you have to actually use the value in some way.
You also need to tweak the async code a bit. This:
async (reports) => {
await reports.forEach((report) => {
// ...
})
}
won't do what you hope, because forEach returns undefined. Even if you shift the async keyword to the forEach callback, all the API requests will be sent in quick succession. Consider using something like this instead, depending on whether you want to wait for the preceding request before sending the next one:
try {
for (const report of reports) {
await this.fetchReportParameters(report.id)
}
} catch (e) {
// handle error
}
This isn't always the right answer: sometimes it's fine to send a bunch of requests in quick succession (perhaps especially if it's a small batch, and/or in the context of HTTP/2). If that's ok with you, you could use:
reports => {
// ...
reports.forEach(report => this.fetchReportParameters(report.id))
}
I need advise for handling errors in front-end of web application.
When I call a service to get the community according to community in web app, I want it to catch an error. For example for catching errors like 404.
There is a service for getting community according to id provided.
getCommunity(id: number) {
return this.http.get(`${this.api}/communities/` + id + ``);
}
that is called in events.ts file
setCommunityBaseUrl() {
this.listingService.getCommunity(environment.communityId).subscribe((data: any) => {
this.communityUrl = data.url + `/` + data.domain;
});
}
The id is provided in environment. Let's say there are 20 communities in total. When I provide id = 1 the events according to community = 1 appears.
export const environment = {
production: ..,
version: 'v2',
apiUrl: '...',
organization: '...',
websiteTitle: '...',
communityId: 1,
googleMapsApiKey: '...'
};
The problem is that when I provide id = null all community events are occurring | all events list in the backend is occurring.
Please, help ^^
When you subscribe you subscribe with an Observer pattern. So the first function you pass in
.subscribe(() => {} );
fires when the Observable calls .next(...)
and after that you can provide another function which will fire whenever the Observable calls .error(...)
so
.subscribe(() => {}, (error) => { handleTheError(error); } );
The this.http.get(...); returns an Observable which will fire the .error(...) on http error
We also know that this.http.get(...) completes or "errors" and it's not an endless one (a one that never completes). So you can make it a promise and manipulate on it promise like.
async getMeSomething(...) {
try {
this.mydata = await this.http.get(...).toPromise();
}
catch(error) {
handleTheError(error)
}
}
But what I really recommend is to use Swagger for your backend and then generate the API Client class with NSwagStudio so you don't have to write the client manually or adjust it or deal with error catching. I use it all the time and it saves us an enormous amount of time
Because you are using ".subscribe" you can create your own error handler and catch the errors like this, directly on the method.
This is an example on how you can use this:
constructor(
private _suiteAPIService: SuitesAPIService,
private _testcaseService: TestcaseService,
public _tfsApiService: TfsApiService,
private _notificationService: NotificationService) { }
errorHandler(error: HttpErrorResponse) {
return observableThrowError(error.message || "Server Error")
}
public something = "something";
GetTestcasesFromSuiteSubscriber(Project, BuildNumber, SuiteId) {
this._suiteAPIService.GetTestResults(Project, BuildNumber, SuiteId).subscribe(
data => {
console.log(data);
this._testcaseService.ListOfTestcases = data;
//Notofication service to get data.
this._notificationService.TestcasesLoaded();
},
error => {
//Here we write som error
return this.something;
}
);
}
I'm having a scenario where I need to periodically call an API to check for a result. I'm using Flowable.interval to create an interval function which calls the API.
However, I'm having trouble with backpressure. In my example below, a new single is created on each tick in the interval. The desired effect is to only call the API if a call is not already in progress
Flowable.interval(1, 1, TimeUnit.SECONDS).flatMap {
System.out.println("Delay $it")
//simulates API call
Single.just(1L).doAfterSuccess {
System.out.println("NEW SINGLE!!!")
}.delay(4, TimeUnit.SECONDS).doAfterSuccess {
System.out.println("SINGLE SUCCESS!!!")
}.toFlowable()
}.subscribeOn(Schedulers.io()).observeOn(Schedulers.computation()).blockingFirst()
I can solve this using a filter variable like so:
var filter = true
Flowable.interval(1, 1, TimeUnit.SECONDS).filter {
filter
}.flatMap {
System.out.println("Delay $it")
Single.just(1L).doOnSubscribe {
filter = true
}.doAfterSuccess {
System.out.println("NEW SINGLE!!!")
}.delay(4, TimeUnit.SECONDS).doAfterSuccess {
System.out.println("SINGLE!!!")
filter = true
}.toFlowable()
}.subscribeOn(Schedulers.io()).observeOn(Schedulers.computation()).blockingFirst()
But it seems like a hacky solution. I've tired applying onBackPressureDrop after the interval function, but it has no effect.
Any suggestions?
You have to constrain flatMap as well:
Flowable.interval(1, 1, TimeUnit.SECONDS)
.onBackpressureDrop()
.flatMapSingle({
System.out.println("Delay $it")
//simulates API call
Single.just(1L).doAfterSuccess {
System.out.println("NEW SINGLE!!!")
}.delay(4, TimeUnit.SECONDS).doAfterSuccess {
System.out.println("SINGLE SUCCESS!!!")
}
}, false, 1) // <----------------------------------------------------------
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.subscribe()
How can I complete function in init before call ready method. My code:
WinJS.Namespace.define("Data", {
source: ""
});
var page = WinJS.UI.Pages.define("/html/page.html", {
init: function (element, options) {
createDataSoucre();
},
ready: function () {
document.getElementById("result").innerHTML = Data.source;
}
});
function createDataSoucre() {
//blah blah (calculate thousands of calculations)
Data.source = result;
}
When I run, page doesn't render "result" tag. I try use promises but it doesn't work for me:
init: function (element, options) {
return new WinJS.Promise.as(createDataSoucre());
}
Thanks for your time.
I tried your code in a simple test project as follows:
(function () {
"use strict";
WinJS.Namespace.define("Data", {
source: ""
});
function createDataSource() {
Data.source = "<ul><li>Item 1</li><li>Item2</li><li>Item3</li></ul>";
}
WinJS.UI.Pages.define("/pages/home/home.html", {
init: function (element, options) {
createDataSource();
},
ready: function (element, options) {
document.getElementById("result").innerHTML = Data.source;
}
});
})();
Everything works as expected, with the bullet list appearing on the page.
However, I believe you're asking how to make your createDataSource function asynchronous in itself, so that it can do your "thousands of calculations" off the UI thread and produce a promise that the init function can return. This way, the page loading process will wait upon the completion of those calculations.
What's needed here is to use new WinJS.Promise rather than WinJS.Promise.as. The as method just wraps a value in a promise so that the value is send to any completed handler you attach, but doesn't create an async function automatically. That's something you have to do.
Let me provide an example from Appendix A of my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript, Second Edition, where Chapter 3 and Appendix A go into all the details about promises. Here's a function that does a long series of calculations using setImmediate to break up the work on the UI thread. (You could also use web workers to put the work on another thread, or use a WinRT component--but I'll leave it to my book to talk about those subjects, which is in Chapter 18 in the section "Implementing Asynchronous Methods").
function calculateIntegerSum(max, step) {
//The WinJS.Promise constructor's argument is a function that receives
//dispatchers for completed, error, and progress cases.
return new WinJS.Promise(function (completeDispatch, errorDispatch, progressDispatch) {
var sum = 0;
function iterate(args) {
for (var i = args.start; i < args.end; i++) {
sum += i;
};
if (i >= max) {
//Complete--dispatch results to completed handlers
Data.source = "Sum is <em>" + sum + "</em>";
completeDispatch(sum);
} else {
//Dispatch intermediate results to progress handlers
progressDispatch(sum);
setImmediate(iterate, { start: args.end, end: Math.min(args.end + step, max) });
}
}
setImmediate(iterate, { start: 0, end: Math.min(step, max) });
});
}
You can do something similar for your own process. The key here is that when your process is complete, you have to call the completeDispatch function that's given to your initializer. In the code above I'm also putting the result into Data.source.
With such a method, your createDataSource function can look like this:
function createDataSource() {
return calculateIntegerSum(100000, 2);
}
Because calculateIntegerSum returns a promise and is implemented to be async, createDataSource will return a promise that you can return from init:
init: function (element, options) {
return createDataSource();
},
I tried this out in a project and it works just fine, with the page loading waiting upon the calculations to complete.