1 the value can not change in promise
for example
var t = function(s) {
var wait = function(dtd) {
var dtd = $.Deferred();
//new a Deferred object in function
var tasks = function() {
alert("complete!");
s = s + "hhh";
dtd.resolve(s); // change the state of deferred object
};
setTimeout(tasks, 5000);
// return promise object
return dtd.promise(s);
};
}
var s = "hhh";
$.when(t(s))
.then(function() {
alert(s);
}).then(function() {
alert(s);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
I can only got "hhh" instead of "hhhhhh"...
2
How to invoke promise chain with different values?like a.then(b(c)).then(f(d))
I put all values in a object and then pass it on chain...
The alert in your $.when is alerting the global variable not the resolve in tasks
Also , you never call wait() and tasks() doesn't return anything.
The return of the promise only returns to wait() which never gets called. Returning to the inner function does not return to the outer function
Also you have no arguments in then() to receive the resolved data.
In order to get data to the second then, you need to return something from the first one
var t = function (s) {
var wait = function () {
var dtd = $.Deferred();
//new a Deferred object in function
var tasks = function () {
alert("complete!");
s = s + "hhh";
dtd.resolve(s); // change the state of deferred object
};
setTimeout(tasks, 2000);
// return promise object
return dtd.promise();
};
// return the promise inside `wait`
return wait()
}
var s = "hhh";
$.when(t(s)).then(function (resolvedData) {
// return to the next then...just because we can
return resolvedData; // must return something if want to access it in next then
}).then(function(previousThenData) {
alert(previousThenData);// alert argument
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
Related
I want to override the Promise constructor and the then method in Promise.
So, whenever someone creates a new Promise object, first my code will be executed and then the original promise constructor will get called.
Similarly, when someone calls .then function of Promise, first my code will get executed and then the callback of then function will get executed.
I tried this
var bind = Function.bind;
var unbind = bind.bind(bind);
function instantiate(constructor, args) {
return new (unbind(constructor, null).apply(null, args));
}
var oldProto = Promise.prototype;
Promise = function() {
console.log("Promise instantiated");
var promise = instantiate(Promise, arguments);
return promise;
};
Promise.prototype = oldProto;
While calling this using
var myFirstPromise = new Promise((resolve, reject) => {
setTimeout(function(){
resolve("Success!"); // Yay! Everything went well!
}, 250);
});
myFirstPromise.then((successMessage) => {
console.log("Yay! " + successMessage);
});
It led to infinite loop with console filled up with Promise instantiated log. I also tried the following:
Promise = function(Promise) {
MyPromise.prototype = Promise.prototype;
function MyPromise(){
console.log("Hello");
var promise = Function.prototype.bind.apply(MyPromise, arguments);
console.log(promise);
return promise;
}
}(Promise);
But, I am not sure whether the constructor overriden is the correct way to do it and how to define the then function for Promise.
my function didnt wait to complete earlier function execution and it is completing.
I have my code is that i am doing some thing wrong:
$scope.abc1 = function(){
var arrayJson = [{'name':'max','age':'12'},{'name':'tax','age':'16'}]
for(var i=0; i<arratJson.length;i++){
var getAddress = $scope.xyz(arratJson[i].name);
}
$scope.createBody();
};
$scope.createBody = function(){
//some more code here
};
$scope.xyz = function(name){
$http({
method: 'GET',
url: 'rest/address',
type:'json',
headers:{'action':'single','name':name},
}).success(function(response){
return response;
}).error(function(response){
});
};
so in this it is not waiting to get address instead of it moving down so how to wait finishing for loop and then call different function.
createBody function called before the $scope.xyz() function returns the value how to wait until loop finishes
This is expected due to asynchronous nature of execution. You should use callbacks to avoid this problem.
You should use the $q service.
first store all $http calls in an array and with $q.all(array) you create a promise that is resolved after all $http promises have resolved.
e.g:
$scope.abc1 = function(){
var arrayJson = [{'name':'max','age':'12'},{'name':'tax','age':'16'}]
var promises = [];
for(var i=0; i<arratJson.length;i++){
promises.push($scope.xyz(arratJson[i].name));
}
$q.all(promises).then($scope.createBody);
};
And on the resolve of this new promise you can call your createBody function.
For this to work You should also change success callback on the $scope.xyz to a then callback and return the promise.
e.g:
$scope.xyz = function(name){
return $http({
method: 'GET',
url: 'rest/address',
type:'json',
headers:{'action':'single','name':name},
}).then(function(response){
return response;
})["catch"](function(response){
});
};
UPDATE
If you don't care if all calls succeed, replace:
$q.all(promises).then($scope.createBody);
With:
$q.all(promises)["finally"]($scope.createBody);
PS: Keep in mind that in the finally callback you don't get the return values of every call, whereas in the then an array will be passed as argument in the callback function which holds in every position a return value of each $http call.
There are two way to achieve this
1)Use async:false
2)Need to use callback
choose your way and enjoy!
You should how promises works in javascript.
$http is an asynchronous function. You must return $http result in $scope.xyz function and use then, success, error function callbacks.
Example:
function xyz() {
return $http(...);
}
xyz().then(function(data) {
address = data.data.address; // in your json dto format
})
more info https://docs.angularjs.org/api/ng/service/$http
hope this helps!
regards
You can use Angular promises.
Include promise status to self created object with deferred value, that has valueOf and toString methods. Last two methods allow to use arithmetic, string and comparison operators.
Object with deferred value:
var DeferredValue = function(initial){
var self = this;
self._value = initial;
var deferred = $q.defer();
self.$promise = deferred.promise;
self.$resolved = false;
self.$resolve = function(value){
deferred.resolve(value);
}
self.$promise.then(function(v){
self._value = v;
deferred = null;
self.$resolved = true;
delete self.$resolve;
return self.$promise;
});
}
DeferredValue.prototype = {
constructor: DeferredValue,
valueOf: function(){
return this._value
},
toString: function(){
return this._value.toString()
}
}
Return this object in your ASYNC function, and resolve them after retrieving data:
var getValue = function(){
var value = new DeferredValue();
$timeout(function(){
value.$resolve(Math.floor(Math.random() * 10))
},1500);
return value;
}
Plunker example
I need to do this: browser have to make N requests to the server, requests mustn't be async, next requests are starting after previous requests will stop.
I can write some function A with for i < N i++ and calling this function A again recursively to do this, but it is not beautifull at all. Also, this called callback hell. I want some more beautifull solution.
I found deffered objects. Some says, it can help me to escape callback hell. I want something like this. setTimeout there is imitate one async request:
function foo1(some) {
debugger;
setTimeout(function foo1async() {
debugger;
deffered.resolve();
}, 500);
return deffered.promise;
}
function foo2(some) {
debugger;
setTimeout(function foo2async() {
debugger;
deffered.reject();
}, 500);
return deffered.promise;
}
function foo3() {
debugger;
setTimeout(function foo3async() {
debugger;
deffered.resolve();
}, 500);
return deffered.promise;
}
var deffered;
function doChain() {
debugger;
deffered = $q.defer();
var promise = deffered.promise;
promise.then(foo1);
promise.then(foo2);
promise.then(foo3);
promise["finally"](function () {
debugger;
});
deffered.resolve();
}
I expect foo1 to be called, then foo1async will be called and resolve deffered object.
foo2 must be called, then foo2async is called.
3.Now I expect, that foo3 wouldn't start, because deffered is rejected in foo2async. After that I expect foo in finally section called.
Actually, I have this:
foo1, foo2 and foo3 are called. Then foo in finally section called. Then foo1async, foo2async and foo3async funtions are called.
How I can get what I am expecting?
Actually, I will have something like this:
for(var i = 0; i < N; i++) {
(function (iter) {
promise.then(function () {
foo(iter);
});
})(i);
}
You got a few things wrong here.
First, you use a deferred to convert a callback-based async function into a promise-based - but each one needs its own deferred.promise and thus its own deferred. Actually, I prefer to use the $q constructor instead:
function fooN(input){
return $q(function(resolve, reject){
setTimeout(function(){
resolve(input + "; some more data");
}, 500);
});
}
(you could use var deferred = $q.defer() as well)
fooN now returns a promise, so you don't need to use $q.defer() anymore.
In fact, if the async function already was promise-based, like $timeout or $http, then you wouldn't have needed a deferred at all, for ex:
function fooN(input){
return $timeout(function(){
return input + "; some more data";
}, 500);
})
So, let's assume that foo1, foo2 and foo3 are implemented like fooN - all returning promises.
To make the calls sequential, you would need to chain promises - not to attach multiple handlers to the some root promise.
I'll break it down for you:
function doChain(){
var foo1Promise = foo1();
var foo2AfterFoo1Promise = foo1Promise.then(foo2);
var foo3AfterFoo2Promise = foo2AfterFoo1Promise.then(foo3);
var promise = foo3AfterFoo2Promise.then(function(finalData){
return doSomeProcessing(finalData); // if needed
});
promise.catch(function(error){
// "rethrow", if can't handle
return $q.reject({msg: "Some error occurred"});
})
return promise;
}
Or, the same, more concise:
function doChain(p){
return foo1(p)
.then(foo2)
.then(foo3)
.then(function(finalData){
return doSomeProcessing(finalData);
})
.catch(function(error){
return $q.reject({msg: "Some error occurred"});
});
}
A "promised" return value of each function is an input to the next chained function.
You can use $q.all method. For instance:
var promises = [promise1, promise2, ...];
$q.all(promises).then(function () {
// do something
});
What happens now is that all foo* promises depend on the single promise; when it gets resolved all are triggered. In ASCII art the dependencies are:
┎ foo1
promise ╁ foo2
┖ foo3
What you want is:
function doChain() {
foo1()
.then(foo2)
.then(foo3)
;
}
No need for the extra promise. No callback hell either!
Please note This is a contrived example.
function longFunc(){
var deferred = $.Deferred();
setTimeout(function(){
console.log("long func completed");
deferred.resolve("hello");
}, 3000);
return deferred.promise();
}
function shortAfterLongFunc(x){
console.log('short func completed with value: ' + x);
return {
a: x
};
}
processFurther(longFunc().then(shortAfterLongFunc)); // send the array for further processing
Problem
I am unable to figure out how to return any kind of object/function for further downstream processing after shortAfterLongFunc completes. I can console.log from shortAfterLongFunc but that's not what i require here.
Fiddle Here
Thanks for looking!
UPDATE:
Okay just to make my question slightly better...this is a simple use case I am looking at:
$.map(['H','E','L','L', 'O'], somefunc). // for each item in array apply somefunc function
function somefunc(x){ // gets called for each value 'H', 'E' etc. in the array by $.map()
var longfunc = function(y){
var deferred = $.Deferred();
setTimeout(function(){
console.log("long func completed");
deferred.resolve(y.toLocaleLowerCase());
}, 3000);
return deferred.promise();
};
var shortAfterLongFunc = function(x){
console.log('short func completed with value: ' + x);
return x;
}
// What should I do here
return longFunc(x).then(shortAfterLongFunc); // must return lower case char to the caller of someFunc
}
somefunc() lets say processes each element of Array to lower case. However, assume this processing takes a long time and async (think setTimeout).. hence a promise to ensure synchronous operation for each element...but on using promise I find myself not able return the transformed value
Just chain another then call, since shortAfterLongFunc returns new promise you can further work with it:
longFunc().then(shortAfterLongFunc).then(function(data) {
console.log('all is complted', data);
});
Demo: http://jsfiddle.net/ebt4pxxa/2/
There is a trick, define an array or object and value it in then:
let Result=[];
let callImport = (load)=>{
import('./component.js').
then((Module)=>{
load[0] = Module;
});};
callImport(Result);
setTimeout(()=> console.log(Result[0]),10);
Here i used setTimeout as await to prevent print Result before promise execution finish.
Here is Codepen sample without setTimeout : https://codepen.io/MNSY22/pen/NWPdvxd
I'm trying to implement a $q.all to run some functions and then return all the outputs into a function attached to the .then at the end.
At the moment the promises look like they're calling in the correct order and the $all .then is occurring at the end, but the results variable comes back with an array of nulls (one for each promise in the $q.all)
JS Fiddle can be found at http://jsfiddle.net/QqKuk/120/ and I'm using angular 1.0.1
The below is a simplified example of the code I have.
Here is my html, simply just there to display some debug text and the output.
<div ng-controller="MyCtrl">
<p>{{fromThen}}</p>
<p>{{fromThen2}}</p>
<p>{{runOrder}}</p>
</div>
and here is my controller, in reality logOne, logTwo, and logThree aren't going to be identical functions.
var myApp = angular.module('myApp', []);
function MyCtrl($scope, $q, $timeout) {
var logOne = function (value) {
$scope.fromThen = $scope.fromThen + value;
var deffered = $q.defer();
deffered.promise.then( function() {
$scope.runOrder = $scope.runOrder + '.logOne()';
$scope.fromThen = $scope.fromThen + value.toUpperCase();
deffered.resolve(value);
return deffered.promise;
});
deffered.resolve();
};
var logTwo = function (value) {
$scope.fromThen = $scope.fromThen + value;
var deffered = $q.defer();
deffered.promise.then( function() {
$scope.runOrder = $scope.runOrder + '.logTwo()';
$scope.fromThen = $scope.fromThen + value.toUpperCase();
deffered.resolve(value);
return deffered.promise;
});
deffered.resolve();
};
var logThree = function (value) {
$scope.fromThen = $scope.fromThen + value;
var deffered = $q.defer();
deffered.promise.then( function() {
$scope.runOrder = $scope.runOrder + '.logThree()';
$scope.fromThen = $scope.fromThen + value.toUpperCase();
deffered.resolve(value);
return deffered.promise;
});
deffered.resolve();
};
$scope.fromThen = '';
$scope.fromThen2 = 'No Value';
$scope.runOrder = '';
$q.all([logOne('One'), logTwo('Two'), logThree('Three')])
.then(function(results) {
$scope.runOrder = $scope.runOrder + '.then';
$scope.fromThen2 = results;
});
}
The output I'm getting is
OneTwoThreeONETWOTHREE
[null,null,null]
.logOne().logTwo().logThree().then
Which to me looks like things are calling in the correct order, so I'm confused why I'm getting nulls in the return value. Am I using the defer.resolve(value) incorrectly?
I've looked at some of the other examples on here but I haven't been able to work out why I'm not getting a result.
Thanks for any help you can give. Since this is also my first post, any tips on what information i should also include (or didn't need to include) would also be appreciated.
Thanks.
Neil
Your issue is that you're not returning your promises from the log functions themselves for $q.all to follow. You're resolving the promises and returning them somewhere, but not to anywhere that's listening. Functions inside calls to .then are called by $q and the return values are sent to the resolution callbacks for the promises .then itself returns. Your promising functions should take the form:
var function = doSomthingDeferred(data) {
var deferred = $q.defer();
doSomethingDeferredWith(data).then(function(deferredResult) {
var processedResult = processDeferredResult(deferredResult);
deferred.resolve(processedResult);
});
return deferred.promise;
}
Alternatively
var function = doSomthingDeferred(data) {
return doSomethingDeferredWith(data).then(function(deferredResult) {
var processedResult = processDeferredResult(deferredResult);
return processedResult;
});
}
In your case, when you doSomethingDeferredWith(data) you:
function doSomethingDeferredWith(data) {
var deferredMore = $q.defer();
$scope.fromThen += data;
deferredMore.resolve($scope.fromThen);
This particular action doesn't really need to be deferred, it finishes immediately, but if you were querying an $http based service, then you'd get your deferredMore promise back:
return deferredMore.promise;
}
Then, after you're done doing that, you're going to get some result as a parameter to a function referenced in a call to .then on a promise like the one returned from doSomethingDeferredWith:
doSomethingDeferredWith(data).then(function(deferredResult) {
Now, because of the way $q works, the call to doSomethingDeferredWith(data) returns a promise, .then is called on that promise and the function passed in is queued up, but is not executed until the current script loop ends. This means that .then is called, the function is queued, and then doSomethingDeferred continues executing, returns, and its calling function then continues executing until the call stack has cleared. Only after that does $q have the opportunity to come back and run all of the callbacks for resolved promises.
In your code, doSomethingDeferred, the various log*** functions, do not actually return a promise. They return undefined. If you instead return the promise we created and will resolve when $q runs the callback instead of at the end of doSomethingDeferred, you'll get your data in the callback for $q.all.
To fix your code, change the deffered.resolve(); calls at the end of each of your log files to return deffered.promise; Then, the return values for the log functions won't be undefined, they'll be promises that $q can follow and run a callback on all three of their .resolve calls at once after all three calls are made, setting your $scope.runFrom2 value to an array of ['One','Two','Three'] as each individual promise resolves with the value from the closure frame of the deferring function.
tl;dr Version
Change the deffered.resolve(); calls at the end of each of your log files to return deffered.promise;