Pass additional parameter to promise chain [duplicate] - javascript

A promise, just for example:
var P = new Promise(function (resolve, reject) {
var a = 5;
if (a) {
setTimeout(function(){
resolve(a);
}, 3000);
} else {
reject(a);
}
});
After we call the .then() method on the promise:
P.then(doWork('text'));
Then doWork function looks like this:
function doWork(data) {
return function(text) {
// sample function to console log
consoleToLog(data);
consoleToLog(b);
}
}
How can I avoid returning an inner function in doWork, to get access to data from the promise and text parameters? Are there any tricks to avoiding the inner function?

Perhaps the most straightforward answer is:
P.then(function(data) { return doWork('text', data); });
Or, since this is tagged ecmascript-6, using arrow functions:
P.then(data => doWork('text', data));
I find this most readable, and not too much to write.

You can use Function.prototype.bind to create a new function with a value passed to its first argument, like this
P.then(doWork.bind(null, 'text'))
and you can change doWork to,
function doWork(text, data) {
consoleToLog(data);
}
Now, text will be actually 'text' in doWork and data will be the value resolved by the Promise.
Note: Please make sure that you attach a rejection handler to your promise chain.
Working program: Live copy on Babel's REPL
function doWork(text, data) {
console.log(text + data + text);
}
new Promise(function (resolve, reject) {
var a = 5;
if (a) {
setTimeout(function () {
resolve(a);
}, 3000);
} else {
reject(a);
}
})
.then(doWork.bind(null, 'text'))
.catch(console.error);

Use currying.
var P = new Promise(function (resolve, reject) {
var a = 5;
if (a) {
setTimeout(function(){
resolve(a);
}, 3000);
} else {
reject(a);
}
});
var curriedDoWork = function(text) {
return function(data) {
console.log(data + text);
}
};
P.then(curriedDoWork('text'))
.catch(
//some error handling
);

The new answer to this question is to use arrow functions (which automatically bind the this and are much more readable). Google for links such as:
https://2ality.com/2016/02/arrow-functions-vs-bind.html
You can set the text like:
this.text = 'text';
P.then(data => doWork(data));
Note: this.text inside doWork will evaluate to 'text'.
This is suggested by jib above and that (or this!) should be the accepted answer now.

Lodash offers a nice alternative for this exact thing.
P.then(_.bind(doWork, 'myArgString', _));
//Say the promise was fulfilled with the string 'promiseResults'
function doWork(text, data) {
console.log(text + " foo " + data);
//myArgString foo promiseResults
}
Or, if you'd like your success function to have only one parameter (the fulfilled promise results), you can utilize it this way:
P.then(_.bind(doWork, {text: 'myArgString'}));
function doWork(data) {
console.log(data + " foo " + this.text);
//promiseResults foo myArgString
}
This will attach text: 'myArgString' to the this context within the function.

use this so you can access global variable inside the promise body
var ref=this;
Example
p.then((data)=>{
var ref=this;
});

Related

Override Promise constructor and its methods

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.

Promises, pass additional parameters to then chain

A promise, just for example:
var P = new Promise(function (resolve, reject) {
var a = 5;
if (a) {
setTimeout(function(){
resolve(a);
}, 3000);
} else {
reject(a);
}
});
After we call the .then() method on the promise:
P.then(doWork('text'));
Then doWork function looks like this:
function doWork(data) {
return function(text) {
// sample function to console log
consoleToLog(data);
consoleToLog(b);
}
}
How can I avoid returning an inner function in doWork, to get access to data from the promise and text parameters? Are there any tricks to avoiding the inner function?
Perhaps the most straightforward answer is:
P.then(function(data) { return doWork('text', data); });
Or, since this is tagged ecmascript-6, using arrow functions:
P.then(data => doWork('text', data));
I find this most readable, and not too much to write.
You can use Function.prototype.bind to create a new function with a value passed to its first argument, like this
P.then(doWork.bind(null, 'text'))
and you can change doWork to,
function doWork(text, data) {
consoleToLog(data);
}
Now, text will be actually 'text' in doWork and data will be the value resolved by the Promise.
Note: Please make sure that you attach a rejection handler to your promise chain.
Working program: Live copy on Babel's REPL
function doWork(text, data) {
console.log(text + data + text);
}
new Promise(function (resolve, reject) {
var a = 5;
if (a) {
setTimeout(function () {
resolve(a);
}, 3000);
} else {
reject(a);
}
})
.then(doWork.bind(null, 'text'))
.catch(console.error);
Use currying.
var P = new Promise(function (resolve, reject) {
var a = 5;
if (a) {
setTimeout(function(){
resolve(a);
}, 3000);
} else {
reject(a);
}
});
var curriedDoWork = function(text) {
return function(data) {
console.log(data + text);
}
};
P.then(curriedDoWork('text'))
.catch(
//some error handling
);
The new answer to this question is to use arrow functions (which automatically bind the this and are much more readable). Google for links such as:
https://2ality.com/2016/02/arrow-functions-vs-bind.html
You can set the text like:
this.text = 'text';
P.then(data => doWork(data));
Note: this.text inside doWork will evaluate to 'text'.
This is suggested by jib above and that (or this!) should be the accepted answer now.
Lodash offers a nice alternative for this exact thing.
P.then(_.bind(doWork, 'myArgString', _));
//Say the promise was fulfilled with the string 'promiseResults'
function doWork(text, data) {
console.log(text + " foo " + data);
//myArgString foo promiseResults
}
Or, if you'd like your success function to have only one parameter (the fulfilled promise results), you can utilize it this way:
P.then(_.bind(doWork, {text: 'myArgString'}));
function doWork(data) {
console.log(data + " foo " + this.text);
//promiseResults foo myArgString
}
This will attach text: 'myArgString' to the this context within the function.
use this so you can access global variable inside the promise body
var ref=this;
Example
p.then((data)=>{
var ref=this;
});

return a promise from .apply method

I'm new to promises and trying to wrap my head around something that should be simple. Maybe someone can hit me in the head with it instead!
I've got these two functions:
//an arbitrary method that runs on delay to mimic an async process
method1 = function( _value, _callback ){
setTimeout(function(){
console.log('dependency1_resolved');
_callback.apply(this, [{valIs:_value}]);
}.bind(this), (Math.random() * 1000));
};
//something that can simple return the object
function returnVal(x){
console.log(x); //this logs 'Object {valIs: 4}'
return x;
}
due to it's async nature, I'd like to run this function in a promise to be used later (maybe even chain later) in my code.
here is my promise:
var promise = new Promise(
function(resolve, reject) {
var x = method1(4, returnVal);
resolve(x);
}
);
promise.then(function(val) {
console.log(val); // undefined
return val;
});
console.log(promise); //Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: undefined}
Does this have anything to do with the .apply method in the first function? What am I missing? Can someone please slap me?
Your returnVal callback doesn't actually do anything.
Instead, you need to actually pass a callback that accepts the value:
var promise = new Promise(
function(resolve, reject) {
method1(4, function(x) { resolve(x); });
}
);
You can also just pass resolve itself as the callback:
var promise = new Promise(
function(resolve, reject) {
method1(4, resolve);
}
);
Your method1 does return nothing, that's why x is undefined. That the returnVal callback does return something is insignificant, its return value is simply ignored by method1.
You will need to call resolve as the callback to make your code work:
new Promise(
function(resolve, reject) {
var x = method1(4, resolve);
}
).then(function(val) {
console.log(val); // undefined
return val;
});
See also How do I return the response from an asynchronous call?

Promise loops (bluebird) - wrap object in async

I have a question about promises.
I am using Bluebird Promise library and build a small async library with it.
I am trying to waterfall promises with the use of a function.
Say I use promises like so:
Promise.resolve()
.then(function () {
console.log("called 1")
return 1;
}).then(function () {
return new Promise (function (res, rej) {
setTimeout(function () {
console.log("called 2")
res(2);
}, 1500);
});
}).then(function () {
console.log("called 3")
return 3;
});
This does in fact wait in a loop and return 1,2,3 in order.
How do I wrap it into a function so that I can do something like this:
a();b();c();, or a().b().c(); where a() puts something onto a chain, b() puts something onto a chain, and c() puts something onto a chain in order.
Since then() returns a new promise, it can all go out of order, so something like
does not work:
var promise = Promise.resolve();
function a () {
promise.then(function () {
// do sync/async
});
}
function b () {
promise.then(function () {
//do sync/async
});
}
function c ...
Thank you for your time :]
I'm not sure what the goal is here. Do you want to have an arbitrary number of things run in sequence where the sequence is known in advance? Or is this a case where the sequence is discovered as you go? The NodeJS streams interface is a lot better for processing an unknown number of things sequentially (#tadman)
Sequence is discoverable, goal is to have ability to call a().b().c() or b().a().d(). Async library on a client-side.
Update: If I do as #zerkms says it does not work as expected. My bad, should work ok, but with lack of context/code did not give me enough info to expand on. Still thank you for your answer, as it gave me more food for thought.
Update: See my answer
You could use a scoped prototype and just add those methods there
Promise.prototype.a = function() {
return this.then(function() {
console.log("called 1")
return 1;
});
};
Promise.prototype.b = function() {
return this.delay(1500).then(function() {
console.log("called 2")
return 1;
});
};
Promise.prototype.c = function() {
return this.then(function() {
console.log("called 3")
return 3;
});
};
I use this to create neat DSLs e.g. with git:
https://gist.github.com/petkaantonov/6a73bd1a35d471ddc586
Thanks to #tadman I came up with this so far, seems to work as I expect it to.
The problem was that I did not update the promise before calling then on it, and it was branching instead of calling it in sequence.
And this is what I wanted - to turn an object that has both sync/async into async to allow chaining. Petka (#Esailija) also shows great example of building DSLs above (semvar version bumping & git pushing) by extending bluebird library, but for my purposes this is enough.
var Sample = function () {
this.promise = Promise.resolve();
};
Sample.prototype.a = function () {
this.then(function () {
console.log("1");
});
return this;
};
Sample.prototype.b = function () {
this.then(function () {
return new Promise(function (res, rej) {
setTimeout(function() {
console.log("2");
res();
}, 500);
});
});
return this;
};
Sample.prototype.c = function () {
this.then(function () {
console.log("3");
})
return this;
};
Sample.prototype.chainPromise = function (func) {
this.promise = this.promise.then(func);
};
var s = new Sample();
s.a().b().c();
or even then instead of chainPromise?
Sample.prototype.then = function (func) {
this.promise = this.promise.then(func);
return this.promise;
};

Bluebird Promise Scope

I have just started using promises in attempt to cleanup some 'callback hell'.
I've decided on trying bluebird and I am running it in the browser but immediately ran into scoping problems.
Is there a way of setting the thisArg in a new Promise? The below example shows that the 'this' value inside the promise resolver is set to the browser window, but I'd like it set to the surrounding scope so I can easily access member variables.
I noticed there is a .bind() method but it only scopes the 'then()' method, not the promise. I also realize I can have 'var me = this' just before the promise and use closure, but I wanted to avoid it if possible.
function MyObject() {
this.value = 7;
}
MyObject.prototype.getValue = function () {
return new Promise(function (resolve) {
// some request/processing that takes a long time
var result = Ajax.request(...);
resolve({
value: this.value,
result: result
});
// 'this' is set to window instead of the instance,
// resulting in this.value as undefined
});
}
var obj = new MyObject();
obj.getValue().then(function (value) {
console.log(value); // preferably outputs 7
})
No, there is not. You can of course use the default approaches, but you shouldn't need to.
When doing heavy processing and getting back the value asynchronously, you want to get a promise for the value. You don't need to set the result value as a property of the original instance.
MyObject.prototype.getValue = function () {
return new Promise(function(resolve) {
// lots of processing to make a `value`
resolve(value); // no `this` at all!
});
};
In case you want to synchronously get the .value that you had set on the instance, you don't need the Promise constructor. Just use Promise.resolve to make a promise for an existing value:
MyObject.prototype.getValue = function () {
// TODO: lots of processing
return Promise.resolve(this.value);
};
Or, in your case, even Promise.method:
// TODO: lots of processing
MyObject.prototype.getValue = Promise.method(function () {
return this.value;
});
This is more a comment then an answer, as it is primary opinion based.
In the rar situations where I need this it would look like this in my code:
Ajax.requestAsync in this case would be a promisifyed version of Ajax.request.
I know this might just move your problem to another place.
MyObject.prototype.getValue = function () {
return Ajax.requestAsync(...)
.bind(this)
.then(function(result) {
return {
value: this.value,
result: result
}
});
}
Or something like this:
MyObject.prototype.getValue = function () {
var returnValue = {
value: this.value
};
return Ajax.requestAsync(...)
.then(function(result) {
returnValue.result = result;
return returnValue;
});
}
A rarely use such constructs:
MyObject.prototype.getValue = function () {
return Promise.all([this, Ajax.requestAsync(...)])
.spread(function(object, result) {
return {
value: object.value,
result: result
};
});
}

Categories