Can anyone help me to understand why the following code is blocking the UI thread...
I've modified the sample application from https://github.com/TrevorDArcyEvans/BlazorSQLiteWasm in order to test the performance of the SQLite database inside a Blazor WebAssembly Progressive Web Application
On a .razor file I have the following
<button onclick="#(async () => CreateMany())" class="btn btn-default btn-sm">
Insert Many
</button>
Which references:
private async void CreateMany()
{
var cars = new List<Car>();
for (int i = 0; i < 1000; i++)
{
cars.Add(new() { Brand = "BMW", Price = 500 });
}
var db = await _dbContextFactory.CreateDbContextAsync();
await db.Cars.AddRangeAsync(cars);
await db.SaveChangesAsync();
_cars.Clear();
_cars.AddRange(db.Cars);
StateHasChanged();
}
When I click the "Insert Many" button it seems to ignore the fact the it's an async void, and it blocks the UI anyway. Am I missing something here?
.NET 6.0
onclick="#(async () => CreateMany())"
This will give you a "... is not awaited" Warning after a Build. Just use onclick="CreateMany"
Am I missing something here?
It would have been better to use async Task CreateMany() ... but that is not essential.
The main problem is that Sqlite is totally synchronous. await db.SaveChangesAsync(); is a lie, it is not async at all.
So your code would probably work as expected with a different database, but there is not much on offer in Wasm.
Task.Run() is also not effective, so alas, you're stuck with this.
Related
I have an async watch that fetches some data from the server. It will batch process the Response in a blocking operation. I am trying to update the view before kicking off the blocking operation, like so:
Vue.component("foo-bar", {
...
watch: {
async things() {
const response = await API.getThings();
this.someUIMessage = `processing ${response.length} things...`;
someBlockingOperation(response);
}
}
}
But this.someUIMessage is not updated in the view until after someBlockingOperation. I stuck an await Vue.nextTick() in between setting the string and calling the blocking op, and this.$forceUpdate(), but without success.
What does work (sometimes! depends on what else is going on in the app) is calling setTimeout(() => someBlockingOperation(response), 0), but that seems like a kludge. Is there a step I'm missing?
You may need to show some more code because your use case is exactly described in the docs - Async Update Queue and await Vue.nextTick() should work
If your someBlockingOperation take too long, it may be worth to think about UI responsiveness anyway and maybe apply a strategy of splitting up you workload into smaller chunks, process only one at a time and use setTimeout(nextBatch, 0) to schedule "next chunk" processing. See this SO question for more details...
My thing is a small project.
In main what it does is that the "server" will get a call from the link directly what will run some functions that will update the database and the data that has to be shown.
I will show what I mean:
function updateData(){
connection.query(`SELECT * FROM muzica WHERE melodie = "${updateList()}"`, function (error, rezultat, fields) {
if (error) {console.log('err la selectare')};
//express output
let data = {
melodie: rezultat[0].melodie,
likes: rezultat[0].likes
}
console.log(data.likes);
app.get('/like', (req,res) =>{
res.json(`${data.likes}`);
});
}
setInterval(()=>{
updateData();
}, 20000)
Uhh, how to explain it, I'm so bad at this...
So, in main, I'm new to back-end work, everything that I did was based on their Documentation as I learn way faster by my needs than some guides and so on.
So, when I or someone does my http://website/like it should show just data.likes, cause that is all that I need, don't count data.melodie (i will clean that later on) after I finish all the code.
Anyway, whenever I do website/like data.likes is not updating to the new database data.likes.
For example, data.likes before were 5, in a few minutes it can be 2 but whenever I call website/like show "5" than its new value 2.
Don't be hash on me, I'm new and I want to learn as much as I can, but I can't understand the above case, by my logic it should ALWAYS show what its in database when it refreshes each 10 seconds(I run this in localhost so I will not stress any online server).
But if there is any better way to check for databases update than "setInterval" please notice me.
It's hard to learn alone without a mentor or someone else to talk about this domain.
Thank you for your time!
Kind regards,
Pulsy
You have things a bit inside out. A request handler such as app.get('/like', ...) goes at the top level and you only ever call it once. What that statement does is register an event handler for any incoming requests with the /like path. When the server receives an incoming request for /like, it will then call the function for this route handler.
You then put inside that route handler the code that you want to run to generate the response and send the response back to the client.
app.get('/like', (req, res) => {
connection.query(`SELECT * FROM muzica WHERE melodie = "${updateList()}"`, function (error, rezultat, fields) {
if (error) {
console.log(error);
res.sendStatus(500);
} else {
//express output
let data = {
melodie: rezultat[0].melodie,
likes: rezultat[0].likes
}
res.json(data);
}
});
});
The endpoints need to be outside of any functions in express.
For example, if you look at the express "hello world" example here, you will see that they have a basic app that only has a single GET endpoint defined which is "/" so you would access it by running "localhost/" or "127.0.0.1/".
In your case, you want your endpoint to be "/like", so you must define something like:
const express = require('express')
const app = express()
const port = 3000
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
app.get('/like', (req, res) => {
// do database stuff and assign data variable
// res.json(data);
}
It will have a callback function called repeatedly to when I start a download task. But It will be so slow that it can't give feedback when touch a button.
Fileio.downloadFile(downloadData[downloadFileIndex].uri, '1.jpg',this.progressFunc.bind(this)).then((DownloadResult)=> {
if (DownloadResult.statusCode == 200) {
let nextDownloadFileIndex = this.props.downloadFileIndex + 1;
this.props.dispatch(DOWNLOADED_A_FILE({
downloadFileIndex:nextDownloadFileIndex,
progressNum:0
}))
}
}).catch((error)=> {
console.log(error)
})
This is my code and the callback function are as be folllowed
progressFunc(DownloadBeginCallbackResult) {
let progressNum = DownloadBeginCallbackResult.bytesWritten / DownloadBeginCallbackResult.contentLength;
if(progressNum<=0.99){
this.props.dispatch(DOWNLOADING_A_FILE({
progressNum:progressNum,
jobId:this.props.jobId
}));
}else{
this.props.dispatch(DOWNLOADING_A_FILE({
progressNum:0,
jobId:this.props.jobId
}));
}
}
I mean I can't get feedback immediately when I touch button. I think that it is because I have a callback function called repeatedly. so js can't handle so many tasks;
It does sound like JS thread is busy doing the request and not able to communicate back to UI thread. One thing you can try is to wrap you on press handler in an InteractionManager.runAfterInteractions(() => ...)
See https://facebook.github.io/react-native/docs/interactionmanager.html
I have a TextBlock on my Windows 8.1 application:
<TextBlock x:Name="some" Text="" TextWrapping="Wrap" />
And I have a code:
some.Text = "example 1";
// working with web service
some.Text = "example 2";
// working with database
When I launch my code I see only "example 1" message. The message "example 2" I can see only after database operation complete.
Is there any way on Windows 8.1 to redraw/refresh/update UI element?
Update:
Here is database operation:
foreach(var record in records)
{
SqliteController.InsertRecord(record);
}
....
public void async InsertRecord(Inspection record)
{
connection.InsertAsync(inspection);
}
Your UI thread seems to be blocked, thus it isn't updeted right away. I've not seen all the code, but from this what you have shown seems that connection.InsertAsync(inspection); is an asynchronous operation. Probably in this situation it may be sufficient just to await your procedure:
foreach (var record in records)
{
await SqliteController.InsertRecord(record);
}
You can also think of redirecting heavy job to other thread, for example like this:
Task.Run(() =>
{
foreach (var record in records)
SqliteController.InsertRecord(record);
});
You may also think of using Paraller.ForEach to speed up your operation.
As for asynchronous programming you will find many usefull information at MSDN and Stephen Cleary's blog.
I'm learning with Titanium to make iPhone/Android apps. I'm using Alloy MVC framework. I never used javascript before, apart from simple scripts in HTML to access the DOM or something like that, so I never needed to structure the code before.
Now, with Titanium, I must use a lot of JS code and I was looking for ways to structure my code. Basically I found 3 ways to do it: prototype, namespace and functions inside functions.
Simple example for each:
Prototype:
NavigationController = function() {
this.windowStack = [];
};
NavigationController.prototype.open = function(windowToOpen) {
//add the window to the stack of windows managed by the controller
this.windowStack.push(windowToOpen);
//grab a copy of the current nav controller for use in the callback
var that = this;
windowToOpen.addEventListener('close', function() {
if (that.windowStack.length > 1)
{
that.windowStack.pop();
}
});
if(Ti.Platform.osname === 'android') {
windowToOpen.open();
} else {
this.navGroup.open(windowToOpen);
}
};
NavigationController.prototype.back = function(w) {
//store a copy of all the current windows on the stack
if(Ti.Platform.osname === 'android') {
w.close();
} else {
this.navGroup.close(w);
}
};
module.exports = NavigationController;
Using it as:
var NavigationController = require('navigator');
var navController = new NavigationController();
Namespace (or I think is something like that, coz the use of me = {}):
exports.createNavigatorGroup = function() {
var me = {};
if (OS_IOS) {
var navGroup = Titanium.UI.iPhone.createNavigationGroup();
var winNav = Titanium.UI.createWindow();
winNav.add(navGroup);
me.open = function(win) {
if (!navGroup.window) {
// First time call, add the window to the navigator and open the navigator window
navGroup.window = win;
winNav.open();
} else {
// All other calls, open the window through the navigator
navGroup.open(win);
}
};
me.setRightButton = function(win, button) {
win.setRightNavButton(button);
};
me.close = function(win) {
if (navGroup.window) {
// Close the window on this nav
navGroup.close(win);
}
};
};
return me;
};
Using it as:
var ui = require('navigation');
var nav = ui.createNavigatorGroup();
Functions inside functions:
function foobar(){
this.foo = function(){
console.log('Hello foo');
}
this.bar = function(){
console.log('Hello bar');
}
}
// expose foobar to other modules
exports.foobar = foobar;
Using it as:
var foobar = require('foobar').foobar
var test = new foobar();
test.bar(); // 'Hello bar'
And now my question is: which is the better to maintain code clean and clear? It seems that prototype is clear an easy to read/mantain. Namespace confuses me a bit but only needs to execute the initial function to be "available" (no use of new while declaring it, I suppose because it returns the object?namespace? "me"). Finally, functions inside functions is similar to the last, so I don't know exactly the difference, but is useful to export only the main function and have all the inside functions available for use it later.
Maybe the last two possibilities are the same, and I'm messing concepts.
Remember that I'm searching for a good way to structure the code and have functions available to other modules and also inside the own module.
I appreciate any clarification.
In the examples that they release, Appcelerator appears to follow the non-prototype approach. You can see it in the examples they have released: https://github.com/appcelerator/Field-Service-App.
I've seen a lot of different approaches to structuring applications in Titanium before Alloy. Since Alloy, I've found following the development team's examples helpful to me.
With that being said, it seems to me that all of this is still under interpretation and open to change and community development. Before Alloy there were some great community suggestions on structuring an app and I believe that it is still open with Alloy. Often when I find someone's example code I see something they did with it that appears to organize it a bit better than I thought of. It seems to make it a bit easier.
I think you should structure your application in a way that makes sense to you. You may stumble on to a better and easier way of developing applications with Alloy, because you are looking at it critically.
I haven't found a lot of extensive Alloy examples, but Field-Service-App makes sense to me. They have a nice separation of the elements in the application beyond MVC. Check it out.