I'm writing an application draws particles on screen in a chemical reaction.
I have written a Particle class and want to handle the async nature of loading images in P5.js in this class.
My thinking was that if I wrap the loadImage() function in a Promise, I should be able to load all of my particle sprites async and then have the draw code execute as soon as the P5 Image object resolves.
I had this code working fine using just callback functionality of loadImage(), but I ultimately have to hand off the image object to a physics library to model particle motion as well as other constructors, so a Promise pattern seemed to be the right solution.
class Particle {
constructor(name) {
// Set properties on the Particle
this.imageUrl = "THE_URL";
this.imageObject = null;
}
loadParticleImage() {
console.log("attempting to load image: " + this.imageUrl)
return new Promise(function (resolve, reject) {
loadImage(this.imageUrl, (result) => {
// Sets the image object property to the result for other methods to access
this.imageObject = result;
// Resolves the Promise with the result
resolve(result);
}, reject(Error("Image not found")));
})
}
drawParticle() {
console.log("attempting to draw particle");
this.loadParticleImage().then(function (imageObject) {
// code to draw image and handoff to physics library
}, function (error) {
console.log("imageObject not defined", error);
});
}
}
And in the setup() function of the main sketch file, I would initialize a particle and draw it using something like:
theParticle = new Particle("Water");
theParticle.drawParticle();
I get a stack error saying that the image could not be loaded and I can't quite figure out why.
attempting to draw particle
particle.js: attempting to load image: img/svg/Water.svg
particle.js: imageObject not defined Error: Image not found
at particle.js
at new Promise (<anonymous>)
at Particle.loadParticleImage (particle.js)
at Particle.drawParticle (particle.js)
at <anonymous>:1:18
I can spot two mistakes in your code:
you are always immediately calling reject(). You probably wanted to pass a callback to loadImage that will reject the promise:
loadImage(this.imageUrl, (result) => {
…
}, () => {
// ^^^^^^^
reject(new Error("Image not found"));
});
the this keyword in your callback is not the one you expect. Use an arrow function for the promise executor callback as well to have this refer to your Particle instance that loadParticleImage was called on:
return new Promise((resolve, reject) => {
// ^^
loadImage(this.imageUrl, result => {
this.imageObject = result;
…
Related
for the p5js rendering engine, if in setup() function I use WEBGL vs P2D, how can I know later in my code what rendering mode I am in? I have wrote generic functions that work across 2D and 3D modes and I want the code to execute in different ways based on the rendering mode.
There probably are more straightforward and elegant ways of doing it but, in a pinch, you can read the drawingContext of the renderer used and see if it's either an instance of WebGLRenderingContext or CanvasRenderingContext2D
const webglSketch = p => {
p.setup = () => {
p.createCanvas(100, 100, p.WEBGL)
p.background('red')
console.log('WEBGL?', p._renderer.drawingContext instanceof WebGLRenderingContext)
console.log('2D?', p._renderer.drawingContext instanceof CanvasRenderingContext2D)
}
}
const twoDSketch = p => {
p.setup = () => {
p.createCanvas(100, 100)
p.background('blue')
console.log('WEBGL?', p._renderer.drawingContext instanceof WebGLRenderingContext)
console.log('2D?', p._renderer.drawingContext instanceof CanvasRenderingContext2D)
}
}
new p5(webglSketch)
new p5(twoDSketch)
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>
If you're not using the instance mode, just check the _renderer global object.
I'm new to Javascript and getting a bit bogged down with Promises in regards to predictions in Keras.JS
Basically i need to get the prediction value out of a promise (Keras Model) so I can pass it to another function. The following code is taken from the Keras.js github.
var predictions = function () {
model
.ready()
.then(() => {
// input data object keyed by names of the input layers
// or `input` for Sequential models
// values are the flattened Float32Array data
// (input tensor shapes are specified in the model config)
console.log('Model ready',x_pred )
var inputData = {
"input": new Float32Array(x_pred)
};
console.log('input data ready')
// make predictions
return model.predict(inputData)
})
.then(outputData => {
// outputData is an object keyed by names of the output layers
// or `output` for Sequential models
// e.g.,
// outputData['fc1000']
//console.log("outputData", outputData)
const output = new Float32Array(outputData.output)
console.log( output )
})
};
Now, the console reads the contents of my prediction - so the model is doing what I want it to do. But I need to take that prediction and pass it to another function. The following just points to my model promise and the output is undefined.
console.log(outpreds, output)
I understand that this is how the promise is meant to work but once the promise has been fulfilled I would really like to be able to do further things with output. unfortunately as I am using Electron/NodeJS I can't access async/await
Can anyone point me in the right direction?
I am writing action creator in react app. where in when i do some api call i need to show the Progress Loader on screen. So, my action creator looks like this.
export const fetchData = (actionType, param) => (dispatch) => {
dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER)); // Show Loader Action
return fetchDataRequest(actionType, param) // Here is Fetch APi Call
.then(responseData => {
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER));
dispatch(Action(recd(actionType), { data: responseData, receivedAt: Date.now() }));
}).catch((error) => {
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
});
};
When i write this piece of code its working as expected, i am dispatching the action as dispatch(fetchData(data)) from component and i am able to show the loader in my Parent Component. What i understand is fetch is returning me the promise. Once the fetch gets completed then i am hiding the loader which is working as expected.
Now, There is scenario where in i need to do some validation where in i don't have to make any api call but all the validation are performed locally.
Here also i want to do the same thing like i need to show loader in my parent component as well when all the validation are done i need to hide the loader.
I have written the same piece of code even actions are getting called but my render function is not getting called.
My Code Looks like:
// This my action creator which will actually do the validation
export const validateAndSaveData = () => {
return ((dispatch, getState) => {
return new Promise((resolve, reject) => {
let saveRecommendDetailsFlag = true;
// here i am dispacthing some action and storing data in my store
saveRecommendDetailsFlag = canSaveData(getState());
if (saveRecommendDetailsFlag) {
resolve('SUCCESS');
} else {
reject('ERROR');
}
});
});
};
And there is one more action creator which i am calling it from from UI Component which will first initiate the show loader action and then perform validation and based on the result of validation i have to hide the loader.
export const saveData = () => {
return ((dispatch) => {
dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER)); // Show Loader Action
return dispatch(validateAndSaveData())
.then(() => {
// Here i m dispatching an action to do some more processing.
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
})
.catch(() => {
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
});
});
};
Everything is working fine but my loader are not coming on the screen. i am not able to figure it out where am i doing wrong.
Can anyone suggest something how can i solve this issue?
I got some workaround using setTimeout func but i don't think that is right approach.
export const saveData = () => {
return ((dispatch) => {
dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER)); // Show Loader Action
setTimeout(()=>return dispatch(validateAndSaveData())
.then(() => {
// Here i m dispatching an action to do some more processing.
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
})
.catch(() => {
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
});
},10);
});
};
Your code looks reasonable, my suspicion is that your validateAndSaveData promise finishes so quickly that there is no visible loader on the screen.
In that case, a timeout is totally reasonable. However, in order to do it properly, I would keep a state on if the loading screen is visible + if it's been shown long enough. You can then remove the loading screen once it is both up for long enough, and the actual event expires.
I'm not sure which action package you're using, so I can't post exact code, but the pseudocode would look something like this:
const delay = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds));
let loadingCounter = 0;
const showLoadingScreen = () => (dispatch) => {
const counter = loadingCounter;
loadingCounter++;
delay(5).then(() => {
if (getStore().loadingScreen.counter === counter) {
dispatch(Action(ActionConstants.PROGRESS_LOADER_DELAY_ELAPSED))
}
})
return dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER, counter))
}
Basically, you would keep track of 3 pieces of state for the loader:
{
counter: 0,
taskCompleted: false,
canHide: false,
}
Counter is saved so that you can disambiguate what happens if you get SHOW_PROGRESS_LOADER while an existing SHOW_PROGRESS_LOADER is in progress.
taskCompleted keeps a record of whether the thing you're waiting on is done, and canHide keeps track if the loader has been visible on the screen long enough.
When you dispatch PROGRESS_LOADER_DELAY_ELAPSED it sets canHide to true, and when you dispatch HIDE_PROGRESS_LOADER it sets taskCompleted to true. (although you may want to rename the latter action). When both canHide and taskCompleted are set to true, only then can the loader go away.
This is a pretty common UI pattern - Try to complete a task quickly. If it takes more than a short amount of time, then throw up a loading dialog. However, the loading dialog is guaranteed to stay up a minimum amount of time to prevent flickering. So the more advanced version of this kind of pattern would be to add another state which doesn't show the progress loader at all unless the call takes more than Y milliseconds.
Hope this makes sense, leave a comment if not :-)
I am loading a promise from d3.csv and then making multiple changes to the returned array in subsequent .then calls.
I need to out put to the html (Angular 2) the sate of the array before each change, I can do this using the ( variable | async ) but it will update with each change and I need to output the state before each change.
I tried to clone the promise, but all clones just point to the same promise. Any variables are out of scope in the changes, and the parent scope is not reachable.
data = d3.csv promise
data.then(methodB()). // HTML | async Output Required of Array before changes
then(methodB()) // HTML | async Output Required of Array before changes
etc..
etc..
etc..
(There are around 15 methods applied to the data as it is munched and analyzed)
What is the best way to achieve this?
Assuming :
you have a starting promise named csvPromise, which delivers array
the methods to be applied are methodA, methodB, methodC etc, each of which accepts Array
each method either returns a mutation of the input array or delivers the mutation via a Promise
changes to the array are cumulative, method-on-method
you have a synchronous function output() which will accept the original array and each mutation
then a pattern like this will do the job :
csvPromise
.then(function(arr) {
output(arr); // observe initial array as delivered by csvPromise
return methodA(arr);
})
.then(function(arr) {
output(arr); // observe array after application of methodA
return methodB(arr);
})
.then(function(arr) {
output(arr); // observe array after application of methodB
return methodC(arr);
})
etc..
etc..
etc..
.then(function(arr) {
output(arr); // observe array after application of final method
}).catch(function(error) {
console.log(error); // any error thrown from anywhere in the chain will arrive here
});
The pattern can be proceduralised by building the chain dynamically as follows :
var methods = [methodA, methodB, methodC, ...]; // list of methods (uncalled at this point)
return methods.reduce(function(promise, method) {
return promise.then(function(arr) {
output(arr); // observe result of previous stage
return method(arr);
});
}, csvPromise)
.then(function(arr) {
output(arr); // observe array after application of final method
}).catch(function(error) {
console.log(error); // any error thrown from anywhere in the chain will arrive here
});
The most likely violation of the assumptions would be that output() was itself asynchronous, in which case :
var methods = [methodA, methodB, methodC, ...]; // list of methods
return methods.reduce(function(promise, method) {
return promise.then(function(arr) {
return output(arr).then(function() {
return method(arr);
});
});
}, csvPromise)
.then(function(arr) {
output(arr); // observe array after application of final method
}).catch(function(error) {
console.log(error); // any error thrown from anywhere in the chain will arrive here
});
This is a sample functionality I need, is it possible??. I am facing problem in debugging it
I need those two functions to be ran before I do any other modification how to do it?
function getPromise() {
var deferred = $.Deferred();
$.when(getPromiseother()).done(function() {
deferred.resolve();
});
deferred.getPromiseother()
}
function getPromise() {
var deferrednext = $.Deferred();
$.when($.ajax(somefunction)).done(function() {
deferrednext.resolve();
});
deferrednext.promise()
}
$.when(getPromise).done(function() {
do something
});
This is a very clumsy way to do this - basically a major point of promises is that they compose and chain and you don't need to $.Deferred anywhere that's not converting a callback API to promises.
$.when($.ajax(somefunction), someOtherPromise).then(function(result, other){
// in here both promises have run to fulfillment and data is available
// so place the rest of your code here
});