I suspect this is very trivial but I have this code:
var latestMth;
d3.csv("data/blah.csv", function(rows) {
x = rows.map(function(d) {
return parseDate(d.dt)
});
latestMth = formatDateOutputMTH(d3.max(d3.values(x)));
});
...
...
.text("Month is " + latestMth);
It works ok displaying "Month is Mar17".
I've attempted to make the above a function but the result now comes through as "Month is undefined". Why is this happening:
var latestMth = function() {
d3.csv("data/blah.csv", function(rows) {
x = rows.map(function(d) {
return parseDate(d.dt)
});
return formatDateOutputMTH(d3.max(d3.values(x)));
});
}
...
...
.text("Month is " + latestMth());
Assuming d3.csv() is not async.
Because you don't return from your function:
var latestMth = function() {
return d3.csv("data/blah.csv", function(rows) { // added return
x = rows.map(function(d) {
return parseDate(d.dt)
});
return formatDateOutputMTH(d3.max(d3.values(x)));
});
}
Note, if it's async, you can use a Promise:
function setLatestMonth() {
return new Promise((resolve, reject) => {
d3.csv("data/blah.csv", function(rows) {
x = rows.map(function(d) {
return parseDate(d.dt)
});
resolve(formatDateOutputMTH(d3.max(d3.values(x))));
});
});
}
setLatestMonth().then(latestMonth => {
// ...
// ...
// ...
.text("Month is " + latestMonth);
});
I don't know d3.csv() - if it already returns a promise, you can simply chain that one instead of creating a new Promise by yourself.
Related
Here is what should be output to console:
1 hello
2 a
3 b
And here is the code for which i should make a class or a function:
var d = new deferred();
d.then(function(res) {
console.log("1 ", res);
var d1 = new deferred();
setTimeout(function() {
d1.resolve("a");
}, 150);
return d1;
});
d.then(function(res) {
console.log("2 ", res);
return "b";
});
d.then(function(res) {
console.log("3 ", res);
return "c";
});
d.resolve("hello");
I should create a class or a
function with name "deferred"
I've already done almost everything except i can't make it get the result from setTimeout
function.
function deferred() {
this.arrfunc = [];
this.buffstr = null;
this.bufffunc;
this.result;
this.then = function(callback) {
this.arrfunc.push(callback);
}
this.wait = function() {
while (this.buffstr == null) {}
return this.buffstr;
}
this.resolve = function(str) {
this.buffstr = str;
while (this.arrfunc.length != 0) {
//console.log(typeof(this.buffstr));
if (typeof(this.buffstr) === "object") {
this.buffstr = this.buffstr.wait();
}
this.bufffunc = this.arrfunc.shift();
this.buffstr = this.bufffunc(this.buffstr);
}
}
}
The main problem in my implemenetation that its somehow stuck in while loop. And don't want to get a result after setTimeout expired.
It seems like maybe you are making this too complicated with all the different state properties. If these are you only requirements, you really only need a queue of callbacks to hold on to all the functions passed into then(). Like regular promises you need to act differently depending on whether the callback returns a regular value or another deferred instance.
function deferred() {
this.callbacks = []
}
deferred.prototype.then = function(cb) {
this.callbacks.push(cb)
}
deferred.prototype.resolve = function(val) {
let f = this.callbacks.shift()
if (f) {
let n = f(val)
if (n instanceof deferred) n.then((v) => this.resolve(v))
else this.resolve(n)
}
}
var d = new deferred("one");
d.then(function(res) {
console.log("1 ", res);
var d1 = new deferred("two");
setTimeout(function() {
d1.resolve("a");
}, 550);
return d1;
});
d.then(function(res) {
console.log("2 ", res);
return "b";
});
d.then(function(res) {
console.log("3 ", res);
return "c";
});
d.resolve("hello")
I want to call an async function from within a do while loop and exit only if the function doesn't return a value.
Is there a way to manage this without having to actually wait outside the callback?
Here's the code that obviously always exits in the first loop since the function hasn't called back yet, when the while () is evaluated:
var i = 0;
do {
var foundListing;
if (i) {
listing.slug = listing.slug + '-' + (i + 1);
}
listingService.getListingBySlug(listing, function(error, pFoundListing) {
if (error) {
return callback(util.errorParser(error));
} else if (Object.keys(pFoundListing).length) {
foundListing = pFoundListing;
i++;
}
});
//Do I have to wait here???
} while (foundListing && Object.keys(foundListing).length);
For Clarification:
The point here is to generate a unique slug. If the slug already exists, i append a number and check again if it exists. When I get to the number that doesn't exist yet, I'm done.
Update:
I found a way using recursion. I posted the working snippet as an answer.
I don't have the possiblity to test it, but maybe a recursive function should do:
const listingService = {
getListingBySlug(listing, callback) {
setTimeout(() => {
if (listing.slug === 'listing-5') {
callback(
false,
{
name: 'Listing 1',
slug: 'listing-1',
}
);
}
else {
callback(false, {});
}
}, 1000);
},
};
function checkListingExists(slug) {
return new Promise((resolve, reject) => {
const listing = { slug };
listingService.getListingBySlug(listing, (error, pFoundListing) => {
if (error) {
reject(error);
} else if (Object.keys(pFoundListing).length) {
resolve(pFoundListing);
} else {
resolve(false);
}
});
});
}
function nextListing(prefix, index) {
checkListingExists(prefix + '-' + index)
.then((listing) => {
if (listing === false) {
nextListing(prefix, index + 1);
} else {
console.log(listing);
}
})
.catch(() => {
// deal with error response
});
}
nextListing('listing', 0);
You should use promise in such cases. You can do something like this.
var DEFERRED = require('deferred');
var deferred = new DEFERRED();
var i =0;
while(1) {
listingService.getListingBySlug(listing, function(error, pFoundListing) {
if (error) {
return callback(util.errorParser(error));
deferred.reject();
break;
} else if (Object.keys(pFoundListing).length) {
i++;
listing.slug = listing.slug + '-' + (i + 1);
if(pFoundListing) {deferred.resolve()}
break;
}
});
deferred.promise.then(function() {
// You will have the listing.slug value here.
});
Btw you should not use Object.keys() to determine whether the object is empty or not. Simply create your own isEmpty method somewhere in utils file and check for the properties. If your pFoundListing is very large it will have the severe performance issue. For small objects (array) you would not notice the difference.
I made it work using recursion as suggested by Giacomo Cosimato.
Here's the snippet that worked:
listingController.js
saveListing: function(listing, callback) {
listingService.findOpenSlug(listing, listing.slug, 1, function(error, listing) {
if (error) {
return callback(util.errorParser(error));
} else {
listingService.saveListing(listing, function(error, savedListing) {
//do some work
});
}
});
}
listingService.js
var classMethods = {
findOpenSlug: function(listing, baseSlug, i, callback) {
listingRepository.getListingBySlug(listing.slug, function(error, foundListing) {
if (error) {
return callback(error);
} else if (Object.keys(foundListing).length) {
listing.slug = baseSlug + '-' + (i + 1)
i++;
classMethods.findOpenSlug(listing, baseSlug, i, callback);
} else {
callback(null, listing);
}
});
},
[...]
}
I have written Angular Service as shown below.
getPropertyDetailsByUsingApiService.js
(function () {
appModule.service('getPropertyDetailsByUsingApiService', ['$http', function ($http) {
this.propertyDetails = function (token, number, street, county, zip) {
var endpointUrl = 'http://my.com/api/Matcher?Token=';
var url = endpointUrl + token + '&Number=' + number + '&Street=' + street + '&County=' + county + '&Zip=' + zip;
return $http.get(url).then(function (data) {
var result = data;
if (result.data[0].Status == 'OK') {
$http.get(endpointUrl + token + '&Krp=' + result.data[0].Result[0].KRP + '&County=' + county)
.then(function (finalData) {
return finalData;
});
}
});
};
}
]);
})();
This is the consuming method :
propertyForm.js
//to call Api
vm.callApi = function () {
var county = _.find(vm.counties, function (c) { return c.id == vm.property.countyId; });
var city = _.find(vm.cities, function (c) { return c.id == vm.property.address.cityId; });
getPropertyDetailsByUsingApiService.propertyDetails(vm.getMd5Hashbytes(), vm.property.address.streetNumber, vm.property.address.streetName,
county.name, city.zipCode).then(function (result) {
vm.propertyDetails = result;
});
};
Q : Issue here is before resolving the promise on service method,it goes to the main method's promise.In other words before resolving 2nd promise on the service method where it goes to the calling method's promise.Can you tell me where is the issue ?
You can rewrite:
return $http.get('url').then(function(r) => { return r;})
as:
var defer = $q.defer();
$http.get('url').then(function(r) => { defer.resolve(r);})
return defer.promise;
It does not make sense in usual case, but in special cases, you can do whatever with this construction:
var defer = $q.defer();
if (smth) {
defer.resolve('test1');
} else {
$http.get('url').then(function(r) => {
if (smth2) {
defer.resolve(r);
} else {
$http.get(..., function(r) => {
defer.resolve(r);
})
}
})
|
return defer.promise;
So, in the first promise on the service, you arent returning the second promise, so the first promise just finishes up and resolves as the method completes, and doesnt wait for the second promise.
return $http.get(url).then(function (data) {
var result = data;
if (result.data[0].Status == 'OK') {
//Add a return here
return $http.get(endpointUrl + token + '&Krp=' + result.data[0].Result[0].KRP + '&County=' + county)
.then(function (finalData) {
return finalData;
});
}
});
I have the following code and in the code when I enter inside the if statement (if (that.cont) ) I get an error of a un-finished promise chain, what can be the reason for this and how should I avoid it?
run: function() {
var oDef = Q.defer();
var Obj = Q(sWUrl);
if (that.cont) {
Obj = that.cont.get(that.cont.transl).then(function(mSet) {
debugger;
if (mSet) {
var lang = mSet.supportedLang;
var dft = mSet.defaultLang;
if (!dft) {
if (lang) {
dft = lang.split(",")[1];
} else {
dft = "en";
}
}
return Q(sWUrl + "&lang=" + window.encodeURIComponent(lang));
} else {
return Q(sWUrl);
}
}, function() {
return Q(sWUrl);
}).then(function(sUri) {
return that.cont.se.pre.get("Pre").then(function(oPreSet) {
return sUri + "&device=" + window.encodeURIComponent(oPreSet.dte);
}).fail(function(error) {
return sUri;
});
});
}
return Obj.then(function(sUri) {
oWin.window.location.href = sUri;
return oWin.oDef.promise;
});
},
I don't know where that error would be coming from, but one thing is for sure - whatever you return from run is never going to resolve, because you never resolve oDef (and you are using the "deferred antipattern").
You also seem to be mistakenly under the assumption that you have to return a promise from your handlers (although you are forgetting to do this in one place), but this is not true. You can just return ordinary values if there's nothing to await.
Give this a try:
run: function() {
var p;
if (that.cont) {
p = that.cont.get(that.cont.transl).then(function(mSet) {
if (mSet) {
var lang = mSet.supportedLang;
var dft = mSet.defaultLang;
if (!dft) {
if (lang) {
dft = lang.split(",")[1];
} else {
dft = "en";
}
}
return sWUrl + "&lang=" + window.encodeURIComponent(lang);
} else {
return sWUrl;
}
}, function() {
return sWUrl;
}).then(function(sUri) {
return that.cont.se.pre.get("Pre").then(function(oPreSet) {
return sUri + "&device=" + window.encodeURIComponent(oPreSet.dte);
}).fail(function(error) {
return sUri;
});
});
} else {
p = Q(sWUrl);
}
return p.then(function(sUri) {
oWin.window.location.href = sUri;
});
},
I have a problem with returning array in Winjs promise and I don't have any idea what is wrong with my code. When i create a promise and do .done or .then my promise does nothing.
Code :
function getSth(array) {
return new WinJS.Promise(function () {
var dbPath = Windows.Storage.ApplicationData.current.localFolder.path + '\\_db.sqlite';
var i = 0;
SQLite3JS.openAsync(dbPath)
.then(function (db) {
console.log('DB opened');
return db.eachAsync('SELECT * FROM sthh;', function (row) {
array[i++] = row.sth;
console.log('Get a ' + row.sth);
});
})
.then(function (db) {
console.log('close the db');
db.close();
}).then(function () {
return array;
});
return array;
})
}
And in other file I just do something like that :
var array = [];
var z = getSth(array).then(function () {
console.log("AAA");
for (var i = 0; i < array.length; console.log("#" + array[i]), i++);
});
I will be very gratefull for any suggestion.
I assume you don't want to return immediately and instead want to return the array once it is full of elements?
I think you want to write code that is more like this:
function getSth(array) {
var dbPath = Windows.Storage.ApplicationData.current.localFolder.path + '\\_db.sqlite';
var i = 0;
return SQLite3JS.openAsync(dbPath)
.then(function (db) {
console.log('DB opened');
return db.eachAsync('SELECT * FROM sthh;', function (row) {
array[i++] = row.sth;
console.log('Get a ' + row.sth);
});
})
.then(function (db) {
console.log('close the db');
db.close();
}).then(function () {
return array;
});
}