Module returning asynchronously initialited object - javascript

I'm having this "design" problem that's driving me crazy.
My goal is having a decoupled RabbitMQ client. It has to be able to init it's connection and "return" a created channel so my publishing module can use it.
Code looks like this (i know that is not the better code but i expect it serves for this explanation).
var createConnection = (function() {
var channel;
var connect = function(){
// amqp connect
// error handling
createChannel();
});
}
var createChannel = function(){
//amqpConn.createConfirmChannel...
}
//pseudo
return{
getChannel : function(){
if(!initiated)
connect();
return channel;
}
}
})();
module.exports = createConnection;
Now, important things:
1- I know this ain't gonna work and i know why, its a simplification.
2- I'm aware that i can accomplish my goals by using async or promises.
3- Maybe has no sense decoupling a rabbit client but is for understanding purposes
That said, my questions:
1- Is there any way i can accomplish this without using other modules?
2- if so, can be accomplished in a fancy and stylish way?
3- Is there any fancy solution that allows 3rd party code executing a simple "publish(exchange, channel, msg)" been sure that connection has been established?
I feel able to work with JS but sometimes you just need do things one way only to know that you can but this is giving me some headache.
Truly thanks and i hope the question was understood :)

One way I've found to handle this is to wrap your asynchronous object in an object that is aware of the asynchronous state of your object and presents the same API regardless of whether or not the asynchronous object has finished initializing.
For example, you could wrap your channel object in another object that presents the same methods but internally checks if the actual channel object is initialized. If it is, use it as normal. If it isn't, wait for it to be initialized and use it as normal. The user of the wrapper object wouldn't need to know if the channel is actually initialized. The main drawback of this is every wrapper method that needs to access channel must be asynchronous even if the method it's accessing on channel is synchronous.
Example:
function initializeChannel() {
return new Promise((resolve, reject) => {
// create, initialize, and resolve channel
});
}
module.exports = { // wrapper
channelPromise: initializeChannel(),
foo(a) {
return this.channelPromise.then((channel) => channel.foo(a));
}
};

Related

WebGL: Callback hell in the resource loader

Please help me deal with this garbage I produced:
Program.prototype.init = function()
{
loadText('../res/shaders/blinnPhong-shader.vsh', function (vshErr, vshText) {
if (vshErr) {
alert('Fatal error loading vertex shader.');
console.error(vshErr);
} else {
loadText('../res/shaders/blinnPhong-shader.fsh', function (fshErr, fshText) {
if (fshErr) {
alert('Fatal error loading fragment shader.');
console.error(fshErr);
} else {
loadJSON('../res/models/dragon.json', function (modelErr, modelObj) {
if (modelErr) {
alert('Fatal error loading model.');
console.error(modelErr);
} else {
loadImage('../res/textures/susanTexture.png', function (imgErr, img) {
if (imgErr) {
alert('Fatal error loading texture.');
console(imgErr);
} else {
this.run = true;
RunProgram(vshText, fshText, img, modelObj);
}
});
}
});
}
});
}
});
};
My actual goal is to abstract the resource loading process for a WebGL program.
That means in the future there will be arrays of meshes, textures, shaders and I want to be able to connect certain dependencies between resources. For example: I want to create two GameObjects One and Two. One uses shaders and is loaded from a mesh but has no texture, whereas Two uses the same shaders as One but uses its own mesh and also needs a texture. What principles could I use to achieve building these dependencies in JavaScript (with asynchronous loading and so on)?
Edit:
So the following is happening with this code: I kept callbacks for now. However this method is part of a Singleton object. I edited the code because in the last else case I am setting a flag of program to true. I keep a global reference of the program object in my main. However due to the callbacks the reference is somehow lost, the global reference keeps its flag to false so the main loop is never reached. It is clearly a problem of the callbacks, since the flag is set when I call "this.run = true" outside the nested callbacks. Any advice on that?
Using modern APIs like Promises, Fetch and sugar like arrow functions, your code can become:
Program.prototype.init = function () {
return Promise.all(
fetch('../res/shaders/blinnPhong-shader.vsh').then(r=>r.text()),
fetch('../res/shaders/blinnPhong-shader.fsh').then(r=>r.text()),
fetch('../res/models/dragon.json').then(r=>r.json()),
new Promise(function (resolve,reject) {
var i = new Image();
i.onload = () => resolve(i);
i.onerror = () => reject('Error loading image '+i.src);
i.src = '../res/textures/susanTexture.png';
})
)
.then(RunProgram);
}
You could spice things up even further by using related ES2017 features like async functions/await or go all in on compatibility by forgoing arrow functions and using seamless polyfills for promises and fetch. For some simple request caching, wrap fetch:
const fetchCache = Object.create(null);
function fetchCached (url) {
if (fetchCache[url])
return Promise.resolve(fetchCache[url]);
return fetch.apply(null,arguments).then(r=>fetchCache[url]=r);
}
Note that you want your resources to be unique so the above mentioned caching still needs another layer of actual GPU resource caching on top of it, you don't want to create multiple shader programs with the same shader code or array buffers with the same vertex data in them.
Your actual core question as to how you could manage dependencies is a bit too broad / application specific to be answered here on SO. In regards to managing the async nature in such an environment I see two options:
Use placeholder resources and seamlessly replace them once the actual resources are loaded
Wait until everything is loaded before you insert the GameObject into the rendering pipeline
Both approaches have their pros and cons, but usually I'd recommend the first option.
You can use promises for this. With the bluebird module, you can convert loadText to a promise function with promise.promiseifyAll(the module loadText is from), or if that is your module, you can make it return a new Promise(function(resolve, reject){})
Using promises, you can make an array of all the promises you want to run and Promise.all([loadText('shader'), loadText("other shader"), ...])
More information on promises

Is providing a Promise as a module's export a valid pattern for asynch initialization in Node.js?

I need to write some modules that load data one time and then provide an interface to that data. I'd like to load the data asynchronously. My application already uses promises. Is providing a promise as the result of requiring a module a valid pattern/idiom?
Example Module:
var DB = require('promise-based-db-module');
module.exports =
DB.fetch('foo')
.then(function(foo){
return {
getId: function(){return foo.id;},
getName: function(){return foo.name;}
};
});
Example Usage:
require('./myPromiseModule')
.then(function(dataInterface){
// Use the data
});
UPDATE:
I've used this for a while now and it works great. One thing I've learned, and it's hinted at in the accepted answer, is that it is good to cache the promise itself, and whenever you want to access the data use then. The first time the data is accessed, the code will wait until the promise is resolved. Subsequent usage of then will return the data immediately. e.g.
var cachedPromise = require('./myPromiseModule');
cachedPromise.then(function(dataInterface){
// Use the data
});
...
cachedPromise.then(function(dataInterface){
// Use the data again somewhere else.
});
This seems like a perfectly good interface for a module who's job is to do a one-time fetch of some data.
The data is obtained async so a promise makes sense for that. The goal is to fetch the data just once and then let all places this module gets used just have access to that original data. A promise works great for that too because it's a one-shot device that remembers its state.
Personally, I'm not sure why you need the getId() and getName() methods when you could just offer direct access to the properties, but either can work.
A downside to this interface is that there is no means of requesting a fresh copy of the data (newly loaded from the DB).

Convert a method with a callback to one that returns a promise with cleanup

I'm trying to write a function that performs an asynchronous task and returns a promise while ensuring cleanup occurs after any callbacks are fulfilled. However to do this, it seems I need to know the callback in advance so I can ensure that it happens before the cleanup happens.
Currently, the general structure of the function looks like this:
function doSomethingWithResourceAsync(someParameter, usePreparedResourceCb) {
var resource = acquireResource(someParameter);
return prepareResourceAsync(resource)
.then(usePreparedResourceCb)
.finally(doCleanup);
function doCleanup() {
releaseResource(resource);
}
}
To call it, I would do this:
doSomethingWithResourceAsync(myParameter, myCallback)
.then(andSoOn);
function myCallback(proxyObj) {
return doMagicAsync(proxyObj);
}
This is the only way I can get it to work.
However, I want to write it in a way that I can chain my callback instead while not having to pass around a cleanup callback. So I'd like to call it like this:
function doSomethingWithResourceHopefullyAsync(myParameter) {
var resource = acquireResource(someParameter);
return prepareResourceAsync(resource)
.finally(doCleanup); // uh oh
function doCleanup() {
releaseResource(resource);
}
}
doSomethingWithResourceHopefullyAsync(myParameter)
.then(myCallback) // too bad, already cleaned up
.then(andSoOn);
This doesn't work however because the cleanup happens before myCallback gets control and messes things up.
If possible, how can I structure my method to accomplish my goal? Or is what I have the best I can do for this situation?
I have a feeling I could use deferreds to accomplish my goal but I don't know how to set that up to make this work.
The API I'm trying to develop is to be consumed by users who won't necessarily know the intricacies of asynchronous methods so I want to hide that as much as possible.
What you have is the disposer pattern. Props for figuring it out on your own :)
"Passing" the callback in is necessary because it creates a scope which is what effectively enables the cleanup. You'd know how the callback is "done" by it returning a promise. The fact you need a scope is fundamental, because it's what well... scopes the cleanup. Binding resource allocation to instantiation via scope (RAII) is a useful technique for what you're doing.
I would do something like:
function withResource(handler){
return acquireResource(). // important to return to chain, like your code
then(handler).finally(cleanup);
}
Which is effectively what you already have.
As the comments suggest, bluebird's using is a very useful abstraction, it returns disposers which give you a lot of power for cleanup and clean up a lot of type errors. I highly recommend it (though I'm obviously biased).

AngularJS $http.get async execution order

I recently did a lot of coding in AngularJS. After some time it started to feel comfortable with it and also got really productive. But unfortunately there is this one thing I don't understand:
Within my project I need to get data through $http.get and a RESTful API server. This is where I started to stumble first. After implementing promise ($q.defer etc and .then) at functions which are processing data that's necessary to continue, I thought I conquered the problem.
But in this code:
$scope.getObservationsByLocations = function() {
var promise = $q.defer();
var locationCount = 0;
angular.forEach($scope.analysisData, function(loc) { // for each location
$http.get($scope.api + 'Device?_format=json', { // get all devices
params: {
location: loc.location.id
}
}).then(function (resultDevices) {
var data = angular.fromJson(resultDevices);
promise.resolve(data);
// for each device in this location
angular.forEach(angular.fromJson(resultDevices).data.entry.map(function (dev) {
http.get($scope.api + 'Observation?_format=json', { // get all observations
params: {
device: dev.resource.id
}
}).then(function (resultObservations) {
var observations = angular.fromJson(resultObservations);
// for each obervation of that device in this location
angular.forEach(observations.data.entry.map(function(obs) {
$scope.analysisData[locationCount].observations.push({observation: obs.resource});
}));
})
}))
});
locationCount++
});
return promise.promise
};
I can't understand in which order the commands are executed. Since I use the Webstorm IDE and it's debugging feature, it would be more accurate to say I don't know why the commands are executed in an order I don't understand.
Thinking simple, everything included in the forEach have to be executed before the return is reached, because $http.get's are connected through .then's. But following the debugging information, the function iterates over locationCount++ and even returns the promise before it goes deeper (meaning after the first .then() ).
What's that all about? Did I misunderstood this part of the AngularJS concept?
Or is this just really bad practice and I should reach out for a different solution?
If the context is important/interesting: Objects are based on i.e. https://www.hl7.org/fhir/2015May/location.html#5.15.3
With JavaScript you can create only single thread applications, although e.g. here they say it is not guaranteed to be like that.
But we are talking about the real world and real browsers, so your code sample is running as a single thread (by the way the same thread is also used for rendering your CSS and HTML, at least in Firefox).
When it comes to an asynchronous call
$http.get($scope.api + 'Device?_format=json', {
it says "hey, I can do that later". And it waits with that because it must go on with the current thread.
Then, once the current task is done with return it finally can start getting the remote data.
Proof? Check this fiddle:
console.log(1);
for (var i=0;i<1000000;i++) setTimeout(function(){
console.log(2);
},0);
console.log(3);
You see the spike with the for loop? This is the moment when it registers the setTimeout asynchronous calls. Still 3 is printed before 2 because the task is not done until the 3 is printed.
The $http.get is asynchronous, so depending on (among other things) how large the fetched data is, the time it takes to 'complete' the get is variable. Hence why there is no saying in what order they will be completed

AngularJs: Have method return synchronously when it calls $http or $resource internally

Is there a way to wait on a promise so that you can get the actual result from it and return that instead of returning the promise itself? I'm thinking of something similar to how the C# await keyword works with Tasks.
Here is an example of why I'd like to have a method like canAccess() that returns true or false instead of a promise so that it can be used in an if statement. The method canAccess() would make an AJAX call using $http or $resource and then somehow wait for the promise to get resolved.
The would look something like this:
$scope.canAccess = function(page) {
var resource = $resource('/api/access/:page');
var result = resource.get({page: page});
// how to await this and not return the promise but the real value
return result.canAccess;
}
Is there anyway to do this?
In general that's a bad idea. Let me tell you why. JavaScript in a browser is basically a single threaded beast. Come to think of it, it's single threaded in Node.js too. So anything you do to not "return" at the point you start waiting for the remote request to succeed or fail will likely involve some sort of looping to delay execution of the code after the request. Something like this:
var semaphore = false;
var superImportantInfo = null;
// Make a remote request.
$http.get('some wonderful URL for a service').then(function (results) {
superImportantInfo = results;
semaphore = true;
});
while (!semaphore) {
// We're just waiting.
}
// Code we're trying to avoid running until we know the results of the URL call.
console.log('The thing I want for lunch is... " + superImportantInfo);
But if you try that in a browser and the call takes a long time, the browser will think your JavaScript code is stuck in a loop and pop up a message in the user's face giving the user the chance to stop your code. JavaScript therefore structures it like so:
// Make a remote request.
$http.get('some wonderful URL for a service').then(function (results) {
// Code we're trying to avoid running until we know the results of the URL call.
console.log('The thing I want for lunch is... " + results);
});
// Continue on with other code which does not need the super important info or
// simply end our JavaScript altogether. The code inside the callback will be
// executed later.
The idea being that the code in the callback will be triggered by an event whenever the service call returns. Because event driven is how JavaScript likes it. Timers in JavaScript are events, user actions are events, HTTP/HTTPS calls to send and receive data generate events too. And you're expected to structure your code to respond to those events when they come.
Can you not structure your code such that it thinks canAccess is false until such time as the remote service call returns and it maybe finds out that it really is true after all? I do that all the time in AngularJS code where I don't know what the ultimate set of permissions I should show to the user is because I haven't received them yet or I haven't received all of the data to display in the page at first. I have defaults which show until the real data comes back and then the page adjusts to its new form based on the new data. The two way binding of AngularJS makes that really quite easy.
Use a .get() callback function to ensure you get a resolved resource.
Helpful links:
Official docs
How to add call back for $resource methods in AngularJS
You can't - there aren't any features in angular, Q (promises) or javascript (at this point in time) that let do that.
You will when ES7 happens (with await).
You can if you use another framework or a transpiler (as suggested in the article linked - Traceur transpiler or Spawn).
You can if you roll your own implementation!
My approach was create a function with OLD javascript objects as follows:
var globalRequestSync = function (pUrl, pVerbo, pCallBack) {
httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function () {
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
pCallBack(httpRequest.responseText);
}
}
httpRequest.open(pVerbo, pUrl, false);
httpRequest.send(null);
};
I recently had this problem and made a utility called 'syncPromises'. This basically works by sending what I called an "instruction list", which would be array of functions to be called in order. You'll need to call the first then() to kick things of, dynamically attach a new .then() when the response comes back with the next item in the instruction list so you'll need to keep track of the index.
// instructionList is array.
function syncPromises (instructionList) {
var i = 0,
defer = $q.defer();
function next(i) {
// Each function in the instructionList needs to return a promise
instructionList[i].then(function () {
var test = instructionList[i++];
if(test) {
next(i);
}
});
}
next(i);
return defer.promise;
}
This I found gave us the most flexibility.
You can automatically push operations etc to build an instruction list and you're also able to append as many .then() responses handlers in the callee function. You can also chain multiple syncPromises functions that will all happen in order.

Categories