promises and deferred in ajax and jquery - promise

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
});

Related

Implement a "promise always" return function

So i have these 2 functions loadScriptWithBluebird and loadBluebird,
loadScriptWithBluebird is supposed to be generic for the main flow of the application, and will always return a promise. I wonder if it is possible with some kind of a pattern to use loadBluebird inside loadScriptWithBluebird
function loadBluebird(callback){
//load the script and callback ...
script.onload = function() {
callback();
};
}
function loadScriptWithBluebird (src){
if(isBluebirdAvailable()){
return new Bluebird(function(resolve, reject){
//load the script and resolve ...
script.onload = function() {
resolve();
};
});
}else{
//issue starts here since i obviously cannot return inside the callback
loadBluebird(function(){
loadScriptWithBluebird(src)
})
}
},
So the flow of the application will look like this :
loadScriptWithBluebird('jquery').then(function(){
//...
});
Thanks.
No, you can't do that, since bluebird wouldn't yet be available when you need to return the promise. So simply ignore that, and rely on the caller of your loadScript function to already have loaded Bluebird. There's not really a way around this.

Ecma 6 Promise complete

I am experimenting with Promise from ES6, but I can't find any alternative to complete as in jQuery ajax. I need to execute function after all the registered handlers with "then".
Thanks!
As mentioned by Bergi, what you want is the disposer pattern. Your central conception of a promise appears to be a bit off, and I think that is making this harder for you to reason about. When you call .then, you are not conceptually "attaching a handler", you are creating a new promise that will by definition resolve after all of its .then handlers have run.
Given your central issue based on code like this:
// a.js
module.exports = function(){
// Where 'Promise.resolve()' is a stand in for your ajax.
return Promise.resolve()
.then(function(){
// Want this to run after 'B'.
});
}
// b.js
var makePromise = require('./a');
module.exports = function specialMakePromise(){
return makePromise().then(function(){
// Should run first.
});
}
They will always run in the wrong order, because by definition, the .then handler from a.js must run and complete before the .then handler from b.js.
One way to approach this problem would instead to structure your code like this:
// a.js
module.exports = function(callback){
return Promise.resolve()
.then(callback)
.then(function(){
// Want this to run after 'B'.
});
}
// b.js
var makePromise = require('./a');
module.exports = function specialMakePromise(){
return makePromise(function(){
// Should run first.
});
}

Sequelize correctly executing multiple creates + updates

I have a cron job that scrapes a list of items on a website and then inserts or updates records in a database. When I scrape the page, I want to create records for new ones that haven't been created yet, otherwise update any existing ones. Currently I'm doing something like this:
// pretend there is a "Widget" model defined
function createOrUpdateWidget(widgetConfig) {
return Widget.find(widgetConfig.id)
.then(function(widget) {
if (widget === null) {
return Widget.create(widgetConfig);
}
else {
widget.updateAttributes(widgetConfig);
}
});
}
function createOrUpdateWidgets(widgetConfigObjects) {
var promises = [];
widgetConfigObjects.forEach(function(widgetConfig) {
promises.push(createOrUpdateWidget(widgetConfig));
});
return Sequelize.Promise.all(promises);
}
createOrUpdateWidgets([...])
.done(function() {
console.log('Done!');
});
This seems to work fine, but I'm not sure if I'm doing this "correctly" or not. Do all promises that perform DB interactions need to run serially, or is how I have them defined ok? Is there a better way to do this kind of thing?
What you're doing is pretty idiomatic and perfectly fine, the only room for improvement is to utilize the fact Sequelize uses Bluebird for promises so you get .map for free, which lets you convert:
function createOrUpdateWidgets(widgetConfigObjects) {
var promises = [];
widgetConfigObjects.forEach(function(widgetConfig) {
promises.push(createOrUpdateWidget(widgetConfig));
});
return Sequelize.Promise.all(promises);
}
Into:
function createOrUpdateWidgets(widgetConfigObjects) {
return Sequelize.Promise.map(widgetConfig, createOrUpdateWidget)
}
Other than that minor improvement - you're chaining promises correctly and seem to have the correct hang of it.

Returning results of d3 request from amd module / requirejs

I'm trying to create a amd module that runs a d3 request (d3.json() in this case) and returns the data from the request. I can't seem to figure out how to make the module wait for the request to finish before it returns the data. As a result I keep getting undefined in my main program when I try to access the data.
define(['app/args'], function(args){
d3.json("resources/waterData.php?stn=" + args.stationID, function (error, data) {
var dataToReturn = {};
//Do some stuff with data
return dataToReturn;
});
});
That is the basic structure of what I'm trying to do. I think the main issue is that the 2nd argument in d3.json is a callback for when the data is loaded, so when I try to return the data, it isn't getting outside the module. I haven't been able to figure out how to get the data from the callback to return it outside the module.
The real issue is that the d3.json function is asynchronous, so you can't just return the processed data from the outside function directly. One way you can work around this is by returning a promise rather than the data itself. You can use the d3.json callback to resolve the promise, and then other modules which depend on the data can register their own callbacks which will run once that promise has been resolved.
For example, if you use jQuery's $.Deferred() you can do the following:
define(['app/args', 'jquery'], function(args, $){
// CREATE DEFERRED OBJECT
var deferred = $.Deferred();
d3.json("resources/waterData.php?stn=" + args.stationID, function (error, data) {
var dataToReturn = {};
//Do some stuff with data
// RESOLVE NOW THAT THE DATA IS READY
deferred.resolve(dataToReturn);
});
// RETURN THE PROMISE
return deferred.promise();
});
Then when you want to use the data, you can require the above module, and register a listener that will fire once the data is ready:
require(['nameOfYourModuleAbove'], function(deferred) {
deferred.done(function(data) {
// DO SOMETHING WITH YOUR DATA
});
})

How can I handle async calls when validating with Backbone.js (uniqueness specifically)

This is relevant for either client or server side apps using backbone. I am attempting to create a validation function with uniqueness checks to MongoDB or some REST call (depending on environment). Both of these calls are async by nature; however, I think I actually need to make it block here for validation purposes. If I don't return anything the validate function will assume validation passed.
My code currently looks like this on the server side:
isUnique: function (key) {
var dfdFindOne = this.findOne({key: this.get(key)}),
dfd = new Deferred();
dfdFindOne.done(function (err, result) {
console.log(result);
dfd.resolve(true);
});
return dfd;
};
... some stuff here....
I feel like I can do some sort of wait till done functionality here before I return... perhaps not though. I wish backbone provided a callback function or something or accepted some sort of deferred type thing.
validate: function() {
var result = undefined;
if(!this.isUnique(key).done(function(){
result = "AHHH not unique!";
});
return result;
}
A possible solution might be to force mongodb's native node client to call things synchronously. I think I can do the same with rest calls... This is probably a bad solution though.
You could call the ajax request and set async:false in this way the return will have value. However to use async:false is evil because could appear as the browser is locked. For server side maybe there are not always workarounds for set async: false
My recommendation is to use your own validation flow instead of Backbone.validate flow, because the validation flow of Backbone was made thinking for synchronous validations only. You could try something like this:
//Code in your Model
isUnique: function (callback) {
var dfdFindOne = this.findOne({key: this.get(key)});
dfdFindOne.done(function (err, result) {
console.log(result);
callback(result);
});
};
validate: function(callback) {
this.isUnique(callback);
}
//trying to validate before save
model.validate(function(result){
if( result == 'whatexpected'){
model.save();
}
});

Resources