In a qooxdoo class, I have a set of asynchronous methods that need to be chained (serialized):
main: function() {
async1();
},
async1: function() {
var json = new qx.data.store.Json("http://...");
json.addListener("loaded", function(event) {
...
async2();
});
},
async2: function() {
// similar to async1
}
As the number of the steps grows, the chain becomes hard to trace, and the code gets unreadable. What we can do is rewrite our code using Promises:
main: function() {
new Promise(this.async1)
.then(function() {
return new Promise(this.async2);
}).then(function() {
return new Promise(this.async3);
}).catch(...);
},
async1: function(resolve, reject) {
var json = new qx.data.store.Json("http://...");
json.addListener("loaded", function(event) {
...
resolve();
});
},
async2: function(resolve, reject) {
// similar to async1
}
This works great but only until we add some real logic. Remember it's a qooxdoo class with a lot of stuff encapsulated into this. But suddenly it turns out that both async* methods and anonymous functions used in then() and catch() have their this context bound to window, a global object. To be able to use actual this, we can perform rebind:
main: function() {
new Promise(this.async1.bind(this))
.then(function() {
this.doSomeStuff();
return new Promise(this.async2.bind(this));
}.bind(this)).then(function() {
return new Promise(this.async3.bind(this));
}.bind(this)).then(function() {
this.doSomeFinalStuff();
}.bind(this)).catch(function() {
this.doStuffOnError();
}.bind(this));
},
async1: function(resolve, reject) {
this.doOtherStuff();
var json = new qx.data.store.Json("http://...");
json.addListener("loaded", function(event) {
...
resolve();
});
}
This finally works, but doh, ugly is the code! Are there any ways to get rid of those manual binds? Why isn't this implicitly bound when we reference this.async1, an instance method?
Check this answer out
Basically, it doesn't look like you're doing anything wrong fundamentally. That's how the context is supposed to work. What you really need is some syntax sugar for your specific use case. You can make these sugar extensions yourself or use a library to do some heavy lifting.
You also could restructure your code like Danbopes suggests and organize it so you're doing less inline-binding. This would allow you to read your flow better.
If you add var self = this; at the top, within all the functions you can refer to the object itself by calling self:
main: function() {
var self = this;
new Promise(self.async1)
.then(function() {
return new Promise(self.async2);
}).then(function() {
return new Promise(self.async3);
}).catch(...);
},
Related
When designing OOP ES 5-6, where I combine prototypes with ES 6 functions. Everything is running in ElectronJS, I do not want a new version that fully supports ES 7 too, so for example the definition of import {trida} from "./cesta" must be solved require ('./ path'). My problem, but it's in Promise.
If I want to program object, I want every object to do what it has and pass the result to the main branch of the program, which contains the column of the whole procedure - object list - Content. If fun enter setTimeout (), you need to use the Promise here, which waits until the function is executed and continues to call another object.
let importing = function(){
this.name = "boot";
}
importing.prototype.start = function(resolve){
this.resolve = resolve;
setTimeout(this.test.bind(this),1000);
console.log('start -------->');
}
importing.prototype.test = function(){
this.resolve('Test');
console.log('Test -------->');
}
importing.prototype.end = function(resolve){
console.log('end -------->');
this.resolve = resolve;
this.resolve('end');
}
let geko;
let scan = new importing();
Promise.resolve(geko)
.then((geko) => new Promise(scan.start.bind(scan)))
.then((geko) => new Promise(scan.end.bind(scan)))
.catch(geko => {
console.log('Error message: ',geko)
})
Here is the problem, I do not want the features to nest in the prototype functions, I want to call every object, nicely in order, clearly. Like any book, it has its Chapter Content, and then the chapters itself and I want to have a quick entry into what I have programmed and did not look at how much a mouse was taken after a week. But for this operation, besides Promise, I also have to use the bind () function because:
importing.prototype.start = function(){
// here this acts as a window object not as importing
// why I have this object called scan.start.bind (scan)
// and here again in setTimeout i have to bind (this) to get it in this.test
// could access this importing - scan object
setTimeout(this.test.bind(this),300);
}
You would find a better way??
You should not pass methods as the argument to the new Promise constructor. If the method is asynchronous, it should return a promise by itself; if it's not asynchronous then you shouldn't be using any promises.
function importing(){
this.name = "boot";
}
importing.prototype.start = function() {
console.log('start -------->');
return new Promise(resolve => {
setTimeout(resolve, 1000); // put the native async call in here, and nothing else!
}).then(() =>
this.test()
);
};
importing.prototype.test = function() {
console.log('Test -------->');
return 'Test';
};
importing.prototype.end = function() {
console.log('end -------->');
return 'end';
}
const scan = new importing();
scan.start().then(() => scan.end()).catch(geko => {
console.log('Error message: ',geko)
});
If the whole project was created as follows:
return new Promise(resolve => {
setTimeout(resolve, 1000);
}).then(() =>
this.test()
);
I would not have much to do with the classic JS procedure, ie the nesting of functions in the functions. That's what I want to avoid. I want content, an outline, when I look at it for a year and I'm going to solve the bugs, I'll know where to start and where the mistakes are going.
let importing = function(){
this.name = "boot";
}
importing.prototype.start = function(resolve){
console.log('Start');
this.resolve = resolve;
setTimeout(this.test.bind(this),1000);
}
importing.prototype.test = function(){
console.log('Test');
this.resolve('Test');
}
importing.prototype.end = function(resolve){
console.log('End');
resolve('end');
}
let scan = new importing();
let promise = function(arg){
return new Promise((resolve, reject)=>{ // The same: new Promise(scan[arg].bind(scan))
return scan[arg].bind(scan)(resolve)
});
}
// so I would imagine chaining. Few braces, simply
// In each called object, if possible, the minimum promissory note
Promise.resolve()
.then(geko => promise('start'))
.then(geko => promise('end'))
.catch(geko => {
console.log('Error message: ',geko)
})
I am working on a javascript project that needs to get some data and process it, but I am having trouble with the asynchronous nature of JavaScript. What I want to be able to do is something like the following.
//The set of functions that I want to call in order
function getData() {
//gets the data
}
function parseData() {
//does some stuff with the data
}
function validate() {
//validates the data
}
//The function that orchestrates these calls
function runner() {
getData();
parseData();
validate();
}
Here I want each function to wait for completion before going on to the next call, as I am running into the situation where the program attempts to validate the data before it has been retrieved. However, I also want to be able to return a value from these functions for testing, so I can't have these functions return a boolean value to check completion. How can I make javascript wait on the function to run to completion before moving on to the next call?
Use promises:
//The set of functions that I want to call in order
function getData(initialData) {
//gets the data
return new Promise(function (resolve, reject) {
resolve('Hello World!')
})
}
function parseData(dataFromGetDataFunction) {
//does some stuff with the data
return new Promise(function (resolve, reject) {
resolve('Hello World!')
})
}
function validate(dataFromParseDataFunction) {
//validates the data
return new Promise(function (resolve, reject) {
resolve('Hello World!')
})
}
//The function that orchestrates these calls
function runner(initialData) {
return getData(initialData)
.then(parseData)
.then(validate)
}
runner('Hello World!').then(function (dataFromValidateFunction) {
console.log(dataFromValidateFunction);
})
Not only are they easy to grasp, it makes total sense from a code readability stand point. Read more about them here. If you are in a browser environment, I recommend this polyfill.
The code you've quoted will run synchronously. JavaScript function calls are synchronous.
So I'm going to assume that getData, parseData, and/or validate involve asynchronous operations (such as using ajax in a browser, or readFile in NodeJS). If so, you basically have two options, both of which involve callbacks.
The first is to just have those functions accept callbacks they'll call when done, for instance:
function getData(callback) {
someAsyncOperation(function() {
// Async is done now, call the callback with the data
callback(/*...some data...*/);
});
}
you'd use that like this:
getData(function(data) {
// Got the data, do the next thing
});
The problem with callbacks is that they're hard to compose and have fairly brittle semantics. So promises were invented to give them better semantics. In ES2015 (aka "ES6") or with a decent promises library, that would look something like this:
function getData(callback) {
return someAsyncOperation();
}
or if someAsyncOperation is not promise-enabled, then:
function getData(callback) {
return new Promise(function(resolve, reject) {
someAsyncOperation(function() {
// Async is done now, call the callback with the data
resolve(/*...some data...*/);
// Or if it failed, call `reject` instead
});
});
}
Doesn't seem to do much for you, but one of the key things is composability; your final function ends up looking like this:
function runner() {
return getData()
.then(parseData) // Yes, there really aren't () on parseData...
.then(validate); // ...or validate
}
usage:
runner()
.then(function(result) {
// It worked, use the result
})
.catch(function(error) {
// It failed
});
Here's an example; it will only work on a fairly recent browser that supports Promise and ES2015 arrow functions, because I was lazy and wrote it with arrow functions and didn't include a Promise lib:
"use strict";
function getData() {
// Return a promise
return new Promise((resolve, reject) => {
setTimeout(() => {
// Let's fail a third of the time
if (Math.random() < 0.33) {
reject("getData failed");
} else {
resolve('{"msg":"This is the message"}');
}
}, Math.random() * 100);
});
}
function parseData(data) {
// Note that this function is synchronous
return JSON.parse(data);
}
function validate(data) {
// Let's assume validation is synchronous too
// Let's also assume it fails half the time
if (!data || !data.msg || Math.random() < 0.5) {
throw new Error("validation failed");
}
// It's fine
return data;
}
function runner() {
return getData()
.then(parseData)
.then(validate);
}
document.getElementById("the-button").addEventListener(
"click",
function() {
runner()
.then(data => {
console.log("All good! msg: " + data.msg);
})
.catch(error => {
console.error("Failed: ", error && error.message || error);
});
},
false
);
<input type="button" id="the-button" value="Click to test">
(you can test more than once)
You should change each function to return a Promise, which will allow your final function to become:
function runner() {
return Promise.try(getData).then(parseData).then(validate);
}
To do that, the body of each function should be wrapped in a new promise, like:
function getData() {
return new Promise(function (res, rej) {
var req = new AjaxRequest(...); // make the request
req.onSuccess = function (data) {
res(data);
};
});
}
This is a very cursory example of how promises might work. For more reading, check out:
2ality's fantastic blog posts: part 1 and part 2
bluebird's documentation on why promises
mdn's documentation on JS' Promise class
Because I'm using a prototype that has functions calling other functions in the same prototype I have to refer to that method using this
The Problem this Created:
But because of that, I have to preserve a context to use this that has me forming very ugly .bind(this) walls.
Here is a simplified example I made for laughs.
Killmyself.prototype.fireLeMissles = function () {
return new Promise(function(resolve,reject) {
this.anotherFunction(param).then(function(result) {
someList.forEach(function(item) {
this.fireLeMissles().then(function(anotherResult){
promiseList.push(anotherResult)
})
},this);
Promise.all(promiseList).then(function(promiseItem){
childPlacesIds.forEach(function(childPlaceId) {
//Do Other Stuff
},this);
});
resolve(result);
}.bind(this).catch(function(err){
console.log("Yea, life sucks sometimes.")
}));
}.bind(this));
}
Killmyself.prototype.another = function(){
//Other stuff
}
You can see because of calls to functions in the same prototype such as this.anotherFunction(... and this.fireLeMissles(... I had to do deep preservation of context,which now (in my much larger version of this) is making this code hard to work with.
Question:
Is this a "man up and get use to the harder aspects of JavaScript" thing - or do you seasoned developers see simple ways that deep binding like this could have been avoided?
If you are using ES6, you can benefit from arrow functions, which preserve the context.
var counter = function () {
this.count = 0;
setInterval( () => { // arrow function
console.log(this.count++); // context is preserved
}, 1000)
}
var counter = new counter();
So, your code would become something like:
Killmyself.prototype.fireLeMissles = function() {
return new Promise((resolve, reject) => {
this.anotherFunction(param).then(result => {
someList.forEach(item => {
this.fireLeMissles().then(anotherResult => {
promiseList.push(anotherResult)
});
});
Promise.all(promiseList).then(promiseItem => {
childPlacesIds.forEach(childPlaceId => {
//Do Other Stuff
});
});
resolve(result);
}).catch(err => {
console.log("Yea, life sucks sometimes.")
});
});
}
For ES5, you can just either use .bind just like the way you did or you can assign this to something else in the function with the desired context, then use that variable inside the inner functions.
Killmyself.prototype.fireLeMissles = function() {
var self = this; /// use `self` instead of `this` from now on.
return new Promise(function(resolve, reject) {
self.anotherFunction(param).then(function(result) {
someList.forEach(function(item) {
self.fireLeMissles().then(function(anotherResult) {
promiseList.push(anotherResult)
})
});
Promise.all(promiseList).then(function(promiseItem) {
childPlacesIds.forEach(function(childPlaceId) {
//Do Other Stuff
});
});
resolve(result);
}).catch(function(err) {
console.log("Yea, life sucks sometimes.")
});
});
}
for starters I do not understand you you need a new Promise.. here, like #loganfsmyth said, I would simply use arrow functions and reduce the complexity:
Killmyself.prototype.fireLeMissles = function (param) {
return this.anotherFunction(param)
.then(someList => {
var promiseList = someList.map( item => this.fireLeMissles(item));
return Promise.all(promiseList);
}).then(childPlacesIds => {
childPlacesIds.forEach(childPlacesId = {
// .... do something;
});
// return something.
}).catch(err => console.log("Yea, life sucks sometimes."));
}
P. S: I am not sure where this param, someList, childPlacesIds is coming from, and assumed that you are initializing that promiseList as empty array.
Mido's answer is good, I just wanted to provide an alternative take on it which I think would be useful to know - using promises for the proxies they are:
Killmyself.prototype.fireLeMissles = function () {
let fn = this.anotherFunction(param);
let others = fn.then(_ => someList.map(this.fireLeMissles, this));
let othersP = Promise.all(others);
othersP.then(/* do OtherStuff */);
return othersP; // or whatever its then returned
}
Of course, this gets even easier with a library like bluebird.
I don't know how to properly phrase it, so I'll just give the example:
I have generator functions that behave as such:
function generateSomething(app) {
return new Promise(function (resolve, reject) {
var cookie;
var login = function (async_cb) {
// Ajax call to login
// This would return a cookie that I need to use for subsequent calls
}
var generate = function (async_cb) {
// This will use the cookie returned from login
}
async.series([
login,
generate,
generate,
generate,
function () {
resolve();
}
]);
});
}
I'll be having many generator files, and there are many functions similar in all of them (for instance, the login). So I'd rather refactor that out into a global helper class. I also really like the async library because of is clean format.
Here comes my problem...
To refactor the login function, I have:
var Helper = {};
module.exports = Helper;
Helper.login = function (app) {
return function (async_cb) {
// Ajax to login
// Once done, call
aysnc_cb();
}
}
And I would use it in my generator function as:
var Helper = require('./helper');
function generateSomething(app) {
return new Promise(function (resolve, reject) {
var cookie;
var generate = function (async_cb) {
// This will use the cookie returned from login
// Once done, call
aysnc_cb();
}
async.series([
Helper.login(app),
generate,
generate,
generate,
function () {
resolve();
}
]);
});
}
The problem though is how do I also return cookie in this example? I realize I would use a Promise and return the result with resolve() but that would mean I cannot use the clean look of async.series([Helper.login, ...]).
Help is appreciated.
The only way I know of to return two objects/values from a single function is to return an array, or object with named values:
return { 'fn':yourobject, 'variable':cookie }
Try setting setting and checking for a global variable with a specific name or within a certain object?
window.specialobject.specialvariable = 'something';
and then deleting the variable when you are done?
delete window.specialobject.specialvariable;
just an idea considering this is async.
I have a click handler that needs to make several async calls, one after another. I've chosen to structure these calls using promises (RSVP, to be precise).
Below, you can see the clickA handler, inside the controller (it's an Ember app, but the problem is more general, I think):
App.SomeController = Ember.Controller.extend({
actions: {
clickA: function() {
var self = this;
function startProcess() {
return makeAjaxCall(url, {
'foo': self.get('foo')
});
}
function continueProcess(response) {
return makeAjaxCall(url, {
'bar': self.get('bar')
});
}
function finishProcess(response) {
return new Ember.RSVP.Promise(...);
}
...
startProcess()
.then(continueProcess)
.then(finishProcess)
.catch(errorHandler);
}
}
});
It looks great, but now I have to add a second action that reuses some of the steps.
Since each of the inner functions needs to access properties from the controller, one solution would be to make them methods of the controller:
App.SomeController = Ember.Controller.extend({
startProcess: function() {
return makeAjaxCall(url, {
'foo': this.get('foo')
});
},
continueProcess: function(response) {
return makeAjaxCall(url, {
'bar': this.get('bar')
});
},
finishProcess: function(response) {
return new Ember.RSVP.Promise(...);
},
actions: {
clickA: function() {
this.startProcess()
.then(jQuery.proxy(this, 'continueProcess'))
.then(jQuery.proxy(this, 'finishProcess'))
.catch(jQuery.proxy(this, 'errorHandler'));
},
clickB: function() {
this.startProcess()
.then(jQuery.proxy(this, 'doSomethingElse'))
.catch(jQuery.proxy(this, 'errorHandler'));
}
}
});
So, my question is: is there a better way? Can I get rid of all those jQuery.proxy() calls somehow?
A solution would be to use a better promise library.
Bluebird has a bind function which lets you bind a context to the whole promise chain (all functions you pass to then or catch or finally are called with this context ).
Here's an article (that I wrote) about bound promises used like you want to keep a controller/resource : Using bound promises to ease database querying in node.js
I build my promise like this :
// returns a promise bound to a connection, available to issue queries
// The connection must be released using off
exports.on = function(val){
var con = new Con(), resolver = Promise.defer();
pool.connect(function(err, client, done){
if (err) {
resolver.reject(err);
} else {
// the instance of Con embeds the connection
// and the releasing function
con.client = client;
con.done = done;
// val is passed as value in the resolution so that it's available
// in the next step of the promise chain
resolver.resolve(val);
}
});
// the promise is bound to the Con instance and returned
return resolver.promise.bind(con);
}
which allows me to do this :
db.on(userId) // get a connection from the pool
.then(db.getUser) // use it to issue an asynchronous query
.then(function(user){ // then, with the result of the query
ui.showUser(user); // do something
}).finally(db.off); // and return the connection to the pool
I may be missing something, but would this solve your issue?
actions: (function() {
var self = this;
function startProcess() { /* ... */ }
function continueProcess(response) { /* ... */ }
function finishProcess(response) { /* ... */ }
function doSomethingElse(response) { /* ... */ }
/* ... */
return {
clickA: function() {
startProcess()
.then(continueProcess)
.then(finishProcess)
.catch(errorHandler);
},
clickB: function() {
startProcess()
.then(doSomethingElse)
.catch(errorHandler));
}
};
}());
Just wrap the actions in an IIFE, and store the common functions there, exposing only the final functions you need. But I don't know Ember at all, and maybe I'm missing something fundamental...
Browsers have a "bind" method on all functions. It's also easy to create a pollyfill for Function#bind.
this.startProcess()
.then(this.continueProcess.bind(this))
.then(this.finishProcess.bind(this))
.catch(this.errorHandler.bind(this));
The jQuery.proxy method essentially does the same thing.