I've been trying to wrap my head around asynchronous programming and the use of promises. To help understand them, I've written some trivial nested code, but have run into a snag.
Here's the code: http://pastebin.com/hBtk9vER
Make sure you install when library (npm install)
var when = require('when');
function promise() {
console.log("Promise");
promiseRead().then(function(string) {
console.log("Inner promise");
console.log(string);
});
}
function promiseRead() {
console.log("PromiseRead");
return baz().then(function() {
console.log("Inner Read");
var deferred = when.defer();
setTimeout(function() {
deferred.resolve("Hello World");
}, 5000);
});
}
function baz() {
console.log("BAZ");
return when(true);
}
promise();
My problem is that console.log(string) is undefined, when I was expecting it to be "Hello World" after promiseRead() resolves. Interestingly, when I remove the timeout, it works as expected. Can anybody help explain this, why the promise function is executing it's code before promiseRead() has finished timeout.
Much appreciated
It looks like you need to return your deferred object in promiseRead()
some updates
var when = require('when');
function promise() {
console.log("Promise");
promiseRead().then(function(string) {
console.log("Inner promise");
console.log(string);
});
}
function promiseRead() {
console.log("PromiseRead");
return baz().then(function() {
console.log("Inner Read");
var deferred = when.defer();
setTimeout(function() {
deferred.resolve("Hello World");
}, 5000);
return deferred.promise;
});
}
function baz() {
console.log("BAZ");
return when(true);
}
promise();
Related
I need to execute 2 functions one after the other with the stuff in function "A" fully completing before the stuff in function "B" executes...
I can't find an example that is not using setTimeout .. which is strange ...
I have the following example below ( from here ) , is it supposed to work ?? How could I test if it is working ? What dummy code could I use to simulate the part "//do stuff with SharePoint JSOM" taking 5 secs to 30 secs ,say .
var a = function() {
var defer = $.Deferred();
//do stuff with SharePoint JSOM
console.log('a() called');
return defer;
};
var b = function() {
var defer = $.Deferred();
console.log('b() called');
return defer;
};
a().then(b);
Simple use a promise (vanilla JS) and chain them with then.
function a() {
return new Promise(function(resolve) {
console.log("wait two seconds ...");
// this timeout is only here for demo purpose ;)
setTimeout(function() {
console.log("A");
resolve();
}, 2000);
});
}
function b() {
console.log("B");
}
a().then(b);
If you want to use jQuery deffered its nearly the same.
function a() {
var defer = $.Deferred();
console.log("wait two seconds ...");
// this timeout is only here for demo purpose ;)
setTimeout(function() {
console.log("A");
defer.resolve();
}, 2000);
return defer;
}
function b() {
console.log("B");
}
a().then(b);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I'm writing a library that takes user-defined functions. I don't have control over what they do, but I want to catch all errors that they cause.
They might also make asynchronous calls like setTimeout, which might throw Errors. I want to catch those errors too.
For example—
// Suppose this is passed as an argument to the module
var userFunction = function() {
setTimeout(function() { throw Error("fail") }, 200);
}
// This is module code
try {
userFunction();
} catch (e) {
console.log("Caught error");
}
—fails with an error and prints a stack trace. The catch doesn't trigger.
I can see how this happens: The error is thrown from the function passed to setTimeout, which is called after the try-catch has passed, in a different context.
How do I work with that? Is it even possible?
If given a function that might call setTimeout or other asynchronous processes within it, how can I catch errors they might throw?
You can use window.onerror to catch all error
try {
setTimeout(function() { throw Error("fail") }, 2000);
} catch (e) {
console.log("Caught");
}
window.onerror = function (){
document.body.innerHTML = "Test";
}
or you can use try catch inside async method
setTimeout(function() {
try {
throw Error("fail");
} catch (e) {
console.log("Caught");
}
}, 2000);
You can use Promises.
With jQuery, something like:
var dfd = jQuery.Deferred();
setTimeout(function() {
dfd.reject("some error msg");
}, 1000);
$.then(dfd.promise()).then(function() {
//blank, this is success callback
}, function(msg) {
//throw your error
});
Full doc: https://api.jquery.com/deferred.promise/
EDIT: can use any Promise implementation. Such as kriswowal/q
https://github.com/kriskowal/q
You don't need to include jQuery. You can use javascripts built in Promise object:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/prototype
you have:
y = x;
x returns a promise:
function() {
...
return promise;
}
All of the asynchronous calls in x are layered:
x is last async handler:
x = function () {
...
// a is second to last async success handler etc..
var j = new Promise (a);
j.then(function() {
// a returned resolve
if (some successful condition) {
resolve(what ever arguments you want to pass y);
} else {
reject(what ever arguments you want to pass y);
},
function (e) {
// error returned by a
reject(e);
}
);
return j;
};
then you can do:
y.then(function() {},
function() {
console.log("Caught");
}
);
I'm using ES6 javascript promises in Chrome and am having trouble understanding why the promise executed within the function _getStatus() is not returning the result argument in the success handler which would result in the alert box containing "done". Instead, I get an alert box that says "undefined".
myNameSpace = function(){
var obj = {
groupA: {
status: "inactive"
},
groupB: {
status: "active"
}
};
function _getStatus(group){
_finishTask().then(function(result){
return result; // doesn't return anything
});
}
function _finishTask(){
var promise = new Promise(function(resolve, reject){
// do some task before resolving
resolve("done");
});
return promise;
};
return{
getStatus:_getStatus
}
}();
$(function(){
alert(myNameSpace.getStatus("groupA")); // why is this "undefined" instead of "done"?
});
Because this is not how Promises work. You need to make sure both _getStatus and _finishTask return Promise objects. Then you will be able to use those promises API methods to execute subsequent code what promise is resolved.
So your code should look something like this:
myNameSpace = function() {
var obj = {
groupA: {
status: "inactive"
},
groupB: {
status: "active"
}
};
function _getStatus(group) {
return _finishTask().then(function(result) {
return result + " and tested";
});
}
function _finishTask() {
return new Promise(function(resolve, reject) {
// do some task before resolving
resolve("done");
});
};
return {
getStatus: _getStatus
}
}();
myNameSpace.getStatus("groupA").then(alert);
Finally, regarding this construction:
return _finishTask().then(function(result) {
return result;
});
_finishTask returns a Promise object, when this promise is resolved you get into then callback. Whatever value you return from this callback becomes a new resolution value for the subsequent success callbacks down the resolution chain.
Demo: http://plnkr.co/edit/K1SWKuTYA3e46RxdzkCe?p=preview
You cant return a result from an asynchronous function as the code running it has already finished by the time the response is returned.
You can however pass in a callback to execute once the code is complete:
function _getStatus(group, callback){
_finishTask().then(function(result){
callback(result);
});
}
$(function(){
myNameSpace.getStatus("groupA", function(result) {
alert(result);
});
});
or use the promise api itself (in this case your _getStatus method is a little redundant):
function _getStatus(group){
return _finishTask();
}
$(function(){
myNameSpace.getStatus("groupA").then(function(result) {
alert(result);
});
});
I thought I had a decent understanding of promises, until I ran into a problem with a simplifed code snippet bellow. I was under the impression that the console.log calls would output first second third, but instead results in second third first.
Can someone explain why the second and third promises are able to continue on without waiting for the first.
var Q = require('q');
(function() {
var Obj = function() {
function first() {
var deferred = Q.defer();
setTimeout(function() {
console.log('in the first')
deferred.resolve();
}, 200);
return deferred.promise;
}
function second() {
return Q.fcall(function() {
console.log('in the second');
})
}
function third() {
return Q.fcall(function() {
console.log('in the third');
})
}
return {
first: first,
second: second,
third: third
}
};
var obj = Obj();
obj.first()
.then(obj.second())
.then(obj.third());
}());
You shouldn't be invoking the function, but pass the function, like this
obj.first()
.then(obj.second)
.then(obj.third);
Output
in the first
in the second
in the third
Considering code snippet below,
function one(){
var prm = new Promise(function(resolve,reject){
});
prm.customKey = function(){
}
return prm;
}
function two(){
return one().then(function(){
//something
});
}
Now calling the function two, returns a promise in which 'customKey' is missing
function three(){
return one();
}
But while doing the same thing in function three(without handling success using 'then'),
returns a promise which has 'customKey' in it.
Can someone clarify me whats really happening and why?
As you can see from "Mozilla Docs" then method returns new Promise (e.g: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then).
If you want to assign a function to retrieve / do something in resolve function do it like this:
var prm = new Promise((resolve, reject) => {
let customKeyFunction = () => {
console.log("I'm custom key function.");
};
resolve(customKeyFunction);
})
From now on you can call this function like that:
function two() {
return one().then(customKey => {
customKey();
})
}