js promise which is not closed correctly - javascript

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

Related

Lebab cannot convert if there are fields

I'm trying to convert es5 to es6 using lebab.
lebab es5.js -o es6.js --transform class
if I convert simple code everything is fine. For example:
var className = function(values) { this.__values = values; };
className.func = function() { return "test"; };
className.func2 = function() { return "test2"; };
className.prototype = {
_values: null,
put: function() { return 0; },
get_length: function() { return this._values.length; }
};
To
class com_cie_json_JsonArray {
constructor(values) {
this._values = values;
}
static func1() {
return "test1";
}
static func2() {
return "test2";
}
put() {
return 0;
}
get_length() {
return this._values.length;
}
}
But if I insert more fields then the Lebab either partially or not translates these pieces at all. This example not translated code.
var className = function(values) {
this.__values = values;
};
className.func = function() {
return "test";
};
className.func2 = function() {
return "test2";
};
$classes[2] = $classes["name.to.className"] = className;
className.__name__ = ["name","to","className"];
className.prototype = {
_values: null,
put: function(value) {
return 0;
},
get_length: function() {
return this._values.length;
},
__class__: className,
__properties__: {get_length:"get_length"}
};
The question is how this type of code will look in ec6. And if it’s possible how to tell the Lebab to convert it.
var className = function() {
};
$classes[2] = $classes["name.to.className"] = className;
className.__name__ = ["name","to","className"];
className.prototype = {
_values: null,
__class__: className,
__properties__: {get_length:"get_length"}
};
$classes[2] = $classes["name.to.className"] = className;
className.__name__ = ["name","to","className"];

How to make a JavaScript class or function that will make the following code work? I can't use promise and await

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")

Move this js to a function

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.

How to take the result of one script and feed it into another?

I'm in way over my head here and need some help to understand what I'm looking at please! (Very new to Javascript!) Here is the situation as I understand it...
I have a script that is selecting a single line from a paragraph of text, and currently produces this alert, where '1' is the selected line:
alert(getLine("sourcePara", 1));
...Instead of triggering an alert I need this selected text to feed into this separate script which is sending data to another browser window. Presently it's taking a text field from a form with the id 'STOCK1', but that can be replaced:
function sendLog() {
var msg = document.getElementById('STOCK1').value;
t.send('STK1', msg);
}
I'm totally confused as to what form this text data is taking on the way out of the first script and have no idea how to call it in as the source for the second... HELP!
All the thanks!
EDIT:
Here is the source code for the Local Connection element;
function LocalConnection(options) {
this.name = 'localconnection';
this.id = new Date().getTime();
this.useLocalStorage = false;
this.debug = false;
this._actions= [];
this.init = function(options) {
try {
localStorage.setItem(this.id, this.id);
localStorage.removeItem(this.id);
this.useLocalStorage = true;
} catch(e) {
this.useLocalStorage = false;
}
for (var o in options) {
this[o] = options[o];
}
this.clear();
}
this.listen = function() {
if (this.useLocalStorage) {
if (window.addEventListener) {
window.addEventListener('storage', this.bind(this, this._check), false);
} else {
window.attachEvent('onstorage', this.bind(this, this._check));
}
} else {
setInterval(this.bind(this, this._check), 100);
}
}
this.send = function(event) {
var args = Array.prototype.slice.call(arguments, 1);
return this._write(event, args);
}
this.addCallback = function(event, func, scope) {
if (scope == undefined) {
scope = this;
}
if (this._actions[event] == undefined) {
this._actions[event] = [];
}
this._actions[event].push({f: func, s: scope});
}
this.removeCallback = function(event) {
for (var e in this._actions) {
if (e == event) {
delete this._actions[e];
break;
}
}
}
this._check = function() {
var data = this._read();
if (data.length > 0) {
for (var e in data) {
this._receive(data[e].event, data[e].args);
}
}
}
this._receive = function(event, args) {
if (this._actions[event] != undefined) {
for (var func in this._actions[event]) {
if (this._actions[event].hasOwnProperty(func)) {
this.log('Triggering callback "'+event+'"', this._actions[event]);
var callback = this._actions[event][func];
callback.f.apply(callback.s, args);
}
}
}
};
this._write = function(event, args) {
var events = this._getEvents();
var evt = {
id: this.id,
event: event,
args: args
};
events.push(evt);
this.log('Sending event', evt);
if (this.useLocalStorage) {
localStorage.setItem(this.name, JSON.stringify(events));
} else {
document.cookie = this.name + '=' + JSON.stringify(events) + "; path=/";
}
return true;
}
this._read = function() {
var events = this._getEvents();
if (events == '') {
return false;
}
var ret = [];
for (var e in events) {
if (events[e].id != this.id) {
ret.push({
event: events[e].event,
args: events[e].args
});
events.splice(e, 1);
}
}
if (this.useLocalStorage) {
localStorage.setItem(this.name, JSON.stringify(events));
} else {
document.cookie = this.name + '=' + JSON.stringify(events) + "; path=/";
}
return ret;
}
this._getEvents = function() {
return this.useLocalStorage ? this._getLocalStorage() : this._getCookie();
}
this._getLocalStorage = function() {
var events = localStorage.getItem(this.name);
if (events == null) {
return [];
}
return JSON.parse(events);
}
this._getCookie = function() {
var ca = document.cookie.split(';');
var data;
for (var i=0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1, c.length);
}
if (c.indexOf(this.name+'=') == 0) {
data = c.substring(this.name.length+1, c.length);
break;
}
}
data = data || '[]';
return JSON.parse(data);
}
this.clear = function() {
if (this.useLocalStorage) {
localStorage.removeItem(this.name);
} else {
document.cookie = this.name + "=; path=/";
}
}
this.bind = function(scope, fn) {
return function () {
fn.apply(scope, arguments);
};
}
this.log = function() {
if (!this.debug) {
return;
}
if (console) {
console.log(Array.prototype.slice.call(arguments));
}
}
this.init(options);
}
If I understand what you are asking for correctly, then I think its a matter of changing your log function to the following:
function sendLog() {
t.send('STK1', getLine("sourcePara", 1));
}
This assumes that getLine is globally accessible.
Alternatively Another approach would be to allow for the sendLog function to take the message as a parameter. In which case, you would change your first script to be:
sendLog(getLine("sourcePara", 1));
And the modified sendLog function would look like this:
function sendLog(msg) {
t.send('STK1', msg);
}
LocalConnection.js should handle transferring the data between windows/tabs. Looks like an an iteresting project:
https://github.com/jeremyharris/LocalConnection.js

Node.js call async function from within do while loop

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);
}
});
},
[...]
}

Categories