I am working on a Node.js project, and I am having issues wrapping a Promise function with a setTimeout function.
My original Promise function:
I want to wrap this function in a call to setTimeout() but am having trouble passing in the Promise object. I need the Promise object and the data object available inside the setTimeout() function, but when I pass them into setTimeout() as parameters i still get the following error:
TypeError: Cannot read property 'then' of undefined
My code:
return Promise.props(data).then(function (data) {
data.companies = data.order && data.order.companies;
if (!data.companies) {
data.companies = {};
data.companies[data.company.id] = data.company;
}
if (data.order) {
if (data.order.contactentry) {
data.order.pointofcontact = data.order.contactentry + ' ' + phone(data.order.contactentryphone);
} else if (data.order.borrowername) {
data.order.pointofcontact = data.order.borrowername + ' ' + phone(data.order.borrowerphone);
} else if (data.order.lockboxcode) {
data.order.pointofcontact = 'Lockbox ' + data.order.lockboxcode
}
}
if (data.part && data.order && data.part.vendor) {
var oid = data.order && data.order.id;
var vid = data.part && data.part.vendor && data.part.vendor.id;
if (!oid || !vid) {
var e = new Error('Could not assemble vendor accept url, order id or part vendor id are missing')
log.error({
error: e,
data,
}, e.message);
throw e;
}
}
return data;
});
The data object is available inside the function when passed in as a parameter, but the Promise object is not.
How can I properly pass in the Promise object to make it available inside setTimeout()?
You're approaching this inside-out. When you want to incorporate non-promise async code (such as setTimeout) into your promise-based code, you should isolate the wrapped non-promise part instead of getting it mixed too deep in the rest of your promise code.
Promise wrapper for setTimeout:
function delay(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
Then you can use it:
return Promise.props(data)
.then(function (result) {
return delay(1000).return(result);
});
Since you appear to be using Bluebird, you can also skip all the setTimeout stuff and use the built-in .delay method:
return Promise.props(data).delay(1000);
Note that either of the above will add an additional 1 second delay to the time it takes to resolve all of the promises in data. If your goal is to just make it so that the minimum total time is 1 second, then you can use my approach from this question:
return Promise.delay(1000).return(Promise.props(data));
I would forget about using the arguments/return value of setTimeout, and just make use of new Promise
Delaying before Promise.props is called:
return new Promise(function (resolve) {
window.setTimeout(function () {
resolve(Promise.props(data));
}, 1000);
});
Or, delaying the result of Promise.props:
return Promise.props(data).then(function (data) {
return new Promise(function (resolve) {
window.setTimeout(function () {
resolve(data);
}, 1000);
});
});
Edit: If you're using Bluebird it looks like they have delay operators built in:
http://bluebirdjs.com/docs/api/delay.html
http://bluebirdjs.com/docs/api/promise.delay.html
Related
I am trying to print all asynchronous calls in a sequence using promise. But i didn't understand whether then implicitly returns a promise or we should explicitly return it.
function fakeAjax(url,cb) {
var fake_responses = {
"file1": "The first text",
"file2": "The middle text",
"file3": "The last text"
};
var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000;
console.log("Requesting: " + url);
setTimeout(function(){
cb(fake_responses[url]);
},randomDelay);
}
function output(text) {
console.log(text);
}
// **************************************
function getFile(file) {
return new Promise((resolve, reject)=>{
fakeAjax(file,resolve);
})
};
let p1= getFile('file1');
let p2= getFile('file2');
let p3= getFile('file3');
p1.then(output) // how does this code work? output doesn't return any promise, but still we can chain it with next .then()
.then( ()=> p2)
.then(output)
.then(()=>p3)
.then(output)
.then(()=>output('complete'))
then returns a promise enabling you to chain the functions that way. It implicitly converts takes the return value of output as the next resolution, and then makes it available in next then. In your case, it will be undefined.
Below is slight modification of your snippet, where I'm showing how then can enable you to create new Promise on the fly based on return value of last promise's resolution.
Here, in output method, after console.log, I have returned the value. Try running the snippet to see it in action.
function fakeAjax (url, cb) {
var fake_responses = {
'file1': 'file2',
'file2': 'file3',
'file3': 'The last text'
}
var randomDelay = 500
console.log('Requesting: ' + url)
setTimeout(function () {
cb(fake_responses[url])
}, randomDelay)
}
function output (text) {
console.log(text)
return text; // return the value
}
// **************************************
function getFile (file) {
console.log('creating prommise for', file)
return new Promise((resolve, reject) => {
fakeAjax(file, resolve)
})
}
var p1 = getFile('file1')
p1.then(output)
.then(getFile)
.then(output)
.then(getFile)
.then(output)
From the documentation:
The then() method returns a Promise. It takes up to two arguments: callback functions for the success and failure cases of the Promise.
If one or both arguments are omitted or are provided non-functions, then then will be missing the handler(s), but will not generate any errors. If the Promise that then is called on adopts a state (fulfillment or rejection) for which then has no handler, a new Promise is created with no additional handlers, simply adopting the final state of the original Promise on which then was called.
I just implemented my first function that returns a promise based on another promise in AngularJS, and it worked. But before I decided to just do it, I spent 2 hours reading and trying to understand the concepts behind promises. I thought if I could write a simple piece of code that simulated how promises worked, I would then be able to conceptually understand it instead of being able to use it without really knowing how it works. I couldn't write that code.
So, could someone please illustrate in vanilla JavaScript how promises work?
A promise is basically an object with two methods. One method is for defining what to do, and one is for telling when to do it. It has to be possible to call the two methods in any order, so the object needs to keep track of which one has been called:
var promise = {
isDone: false,
doneHandler: null,
done: function(f) {
if (this.isDone) {
f();
} else {
this.doneHandler = f;
}
},
callDone: function() {
if (this.doneHandler != null) {
this.doneHandler();
} else {
this.isDone = true;
}
}
};
You can define the action first, then trigger it:
promise.done(function(){ alert('done'); });
promise.callDone();
You can trigger the action first, then define it:
promise.callDone();
promise.done(function(){ alert('done'); });
Demo: http://jsfiddle.net/EvN9P/
When you use a promise in an asynchronous function, the function creates the empty promise, keeps a reference to it, and also returns the reference. The code that handles the asynchronous response will trigger the action in the promise, and the code calling the asynchronous function will define the action.
As either of those can happen in any order, the code calling the asynchronous function can hang on to the promise and define the action any time it wants.
For the simplicity to understand about the promises in Javascript.
You can refer below example. Just copy paste in a new php/html file and run.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function test(n){
alert('input:'+n);
var promise = new Promise(function(fulfill, reject) {
/*put your condition here */
if(n) {
fulfill("Inside If! match found");
}
else {
reject(Error("It broke"));
}
});
promise.then(function(result) {
alert(result); // "Inside If! match found"
}, function(err) {
alert(err); // Error: "It broke"
});
}
</script>
</head>
<body>
<input type="button" onclick="test(1);" value="Test"/>
</body>
</html>
Click on Test button,
It will create new promise,
if condition will be true it fulfill the response,
after that promise.then called and based on the fulfill it will print the result.
In case of reject promise.then returns the error message.
Probably the simplest example of promises usage looks like that:
var method1 = (addings = '') => {
return new Promise(resolve => {
console.log('method1' + addings)
resolve(addings + '_adding1');
});
}
var method2 = (addings = '') => {
return new Promise(resolve => {
console.log('method2' + addings)
resolve(addings + '_adding2');
});
}
method1().then(method2).then(method1).then(method2);
// result:
// method1
// method2_adding1
// method1_adding1_adding2
// method2_adding1_adding2_adding1
That's basic of basics. Having it, you can experiment with rejects:
var method1 = (addings = '*') => {
return new Promise((resolve, reject) => {
console.log('method1' + addings)
resolve(addings + '_adding1');
});
}
var method2 = (addings = '*') => {
return new Promise((resolve, reject) => {
console.log('method2' + addings)
reject();
});
}
var errorMethod = () => {
console.log('errorMethod')
}
method1()
.then(method2, errorMethod)
.then(method1, errorMethod)
.then(method2, errorMethod)
.then(method1, errorMethod)
.then(method2, errorMethod);
// result:
// method1*
// method2*_adding1
// errorMethod
// method2*
// errorMethod
// method2*
As we can see, in case of failure error function is fired (which is always the second argument of then) and then next function in chain is fired with no given argument.
For advanced knowledge I invite you here.
please check this simple promise code. this will help you to better understand of promise functionality.
A promise is an object that may produce a single value some time in the future: either a resolved value, or a reason that it’s not resolved. A promise may be in one of 3 possible states: fulfilled, rejected, or pending. Promise users can attach callbacks to handle the fulfilled value or the reason for rejection.
let myPromise = new Promise((resolve, reject)=>{
if(2==2){
resolve("resolved")
}else{
reject("rejected")
}
});
myPromise.then((message)=>{
document.write(`the promise is ${message}`)
}).catch((message)=>{
document.write(`the promise is ${message}`)
})
check this out
This question already has answers here:
Why does the Promise constructor need an executor?
(2 answers)
Closed 6 years ago.
I wish to return a Promise which is self-resolved at a later time, but it seems that my syntax is invalid, and I'm curious what a better implementation would be. Why is an executor required for the Promise constructor?
promise = new Promise() is invalid because I need to supply a function
function getDetails (someHash) {
var url = "http://somewebsite.com/" + someHash,
promise = new Promise();
makeAjaxRequest(url, function (response) {
promise.resolve(response.data);
});
setTimeout(function () {
promise.reject("timeout");
}, 500);
return promise;
}
function makeAjaxRequest (url, callback) {
var someResponse = {data: "some data"};
setTimeout(function () {
callback(someResponse);
}, 200);
}
Is there a better way to implement this functionality?
Note: If you want to convert a callback API to promises see this question.
Let's start with something that should be said from the get go. An executor is not required in order to design promises. It is entirely possible to design a promises implementation that does something like:
let {promise, resolve, reject} = Promise.get();
If you promise not to tell anyone, I'll even let you in on a little secret - this API even exists from a previous iteration of the spec and in fact even still works in Chrome:
let {promise, resolve, reject} = Promise.defer();
However, it is being removed.
So, why do I need to pass an executor?
I just answered your other question about why an executor is an interesting design. It's throw-safe and it lets you take care of interesting things.
Can I still get the resolve, reject functions? I need those
In my experience, most of the times I needed resolve/reject I didn't actually need them. That said - I did in fact actually need them a couple of times.
The specifiers recognized this and for this reason the executor function is always run synchronously. You can get the .defer interface it just isn't the default:
function defer() {
let resolve, reject, promise = new Promise((res, rej) => {
[resolve, reject] = [res, rej];
});
return {resolve, reject, promise};
}
Again, this is typically not something you want to do but it is entirely possible that you have a justifiable use case which is why it's not the default but completely possible.
Your actual code
I would start with implementing things like timeout and a request as primitives and then compose functions and chain promises:
function delay(ms) {
return new Promise(r => setTimeout(r, ms));
}
function timeout(promise, ms) {
return Promise.race([
promise,
delay(ms).then(x => { throw new Error("timeout"); })
]);
}
function ajax(url) { // note browsers do this natively with `fetch` today
return new Promise((resolve, reject) => { // handle errors!
makeAjaxRequest(url, (result) => {
// if(result.isFailure) reject(...);
if(result.status >= 400) reject(new Error(result.status));
else resolve(result.data);
});
});
}
Now when we promisified the lowest level API surface we can write the above code quite declaratively:
function getDetails (someHash) {
var ajax = makeAjaxRequest("http://somewebsite.com/" + someHash);
return timeout(ajax, 500);
}
You need to pass a function to the Promise constructor (more info), which will get called to provide the resolve and reject functions:
function getDetails (someHash) {
var url = "http://somewebsite.com/" + someHash;
return new Promise(function(resolve, reject) {
makeAjaxRequest(url, function(err, response) {
if (err)
reject(err);
else
resolve(response.data);
});
setTimeout(function () {
reject("timeout");
}, 500);
});
}
function makeAjaxRequest (url, callback) {
var someResponse = {data: "some data"};
setTimeout(function () {
callback(null, someResponse);
}, 200);
}
I've also taken the liberty to make makeAjaxRequest use the standard convention of passing errors as first argument (because I assume that at some point you want to replace the setTimeout() with an actual AJAX request).
I am new to nodejs and using promise and actually this is my first real app with nodejs.
So i have been reading all day and i am a bit confused.
So this is my module :
function User() {
var self = this;
self.users = {};
self.start = function (user, botId) {
return new Promise(function () {
return get(user).then(function (data) {
debug(data);
if (data.botId.indexOf(botId) === false) {
return Repo.UserBotModel.addUser(user.id, botId).then(function () {
data.botId.push(botId);
return data;
});
} else
return data;
});
});
};
self.getDisplayName = function (user) {
if (user.real_name)
return user.real_name;
if (user.last_name)
return user.firstname + ' ' + user.last_name;
return user.first_name;
};
/**
* check if user exist in our database/memory cache and return it,
* otherwise insert in the database and cache it in memory and the return it
* #param user
*/
function get(user) {
return new Promise(function () {
//check if user is loaded in our memory cache
if (self.users.hasOwnProperty(user.id))
return self.users[user.id];
else {
//get from database if exist
return Repo.UserModel.get(user.id).then(function (rows) {
if (rows && rows.length) {
//user exist cache it and resolve
var data = rows[0];
if (data.botId && data.botId.length)
data.botId = data.botId.split(',');
else
data.botId = [];
self.users[user.id] = data;
//------------------------------ code execution reaches here
return data;
}
else {
//user dose not exist lets insert it
return Repo.UserModel.insert(user).then(function (result) {
return get(user);
});
}
});
}
});
}
}
I call the start method witch calls the private get method the call reaches return data;(marked with comment) but then function dose not gets executed in the start method ???
So what am i doing wrong?
UPDATE : Sorry I forgot to mention that I am using bluebird and not the native promise if that makes a difference?
You cannot return from the Promise constructor - you have to call resolve (expected to happen asynchronously). You're not supposed to use the Promise constructor at all here. You can just omit it, and it should work.
The methods from your Repo.UserModel already return promises, so you do not have to create new ones using new Promise.
You can read the values inside those promises using then.
then also provides a way to transform promises. If you return a value in a function passed to then, then will return a new promise that wraps the value you returned. If this value is a promise, it will be awaited.
To convert a value to a promise, you can use Promise.resolve.
Knowing that, you can simplify get like so:
function get(user) {
if (...) {
return Promise.resolve(...)
} else {
return Repo.UserModel.get(...).then(function(rows) {
...
return ...
})
}
}
This version of getwill always return a promise that you can use like so:
get(...).then(function(resultOfGet) {
// process resultOfGet
})
I think this is a really stupid question but I'm having a hard time wrapping my head around promises.
I'm using Q (for nodejs) to sync up a couple of async functions.
This works like a charm.
var first = function () {
var d = Q.defer();
fs.readdir(path,function(err,files){
if(err) console.log(err);
d.resolve(files);
});
return d.promise;
};
var second = function (files) {
var list = new Array;
files.forEach(function(value, index){
var d = Q.defer();
console.log('looking for item in db', value);
db.query(
'SELECT * FROM test WHERE local_name =? ', [value],{
local_name : String,
},
function(rows) {
if (typeof rows !== 'undefined' && rows.length > 0){
console.log('found item!', rows[0].local_name);
d.resolve(rows[0]);
} else {
var itemRequest = value;
getItemData(itemRequest);
}
}
);
list.push(d.promise);
});
return Q.all(list);
};
first()
.then(second)
.done(function(list){
res.send(list);
});
The problem I have is with this little function:
getItemData(itemRequest)
This function is filled with several of callbacks. The promise chain runs through the function just fine but ignores all the callbacks I use ( eg several XHR calls I make in the function).
A simplified version of the function looks like this (just to give you an idea):
function getItemData(itemRequest){
helper.xhrCall("call", function(response) {
var requestResponse = JSON.parse(response)
, requestInitialDetails = requestResponse.results[0];
downloadCache(requestInitialDetails,function(image) {
image = localImageDir+requestInitialDetails.image;
helper.xhrCall("call2", function(response) {
writeData(item,image,type, function(){
loadData(item);
});
});
} else {
writeData(item,image,type, function(){
loadData(item);
});
}
});
});
The xhr function I use looks like this:
xhrCall: function (url,callback) {
var request = require("request")
, colors = require('colors');
request({
url: url,
headers: {"Accept": "application/json"},
method: "GET"
}, function (error, response, body) {
if(!error){
callback(body);
}else{
console.log('Helper: XHR Error',error .red);
}
});
}
So my questions:
Can I leave the function unaltered and use the callbacks that are in place ánd the promise chain?
Or do I have to rewrite the function to use promises for the XHR?
And if so, How can I best write my promise chain? Should I reject the initial promise in the forEach?
Again, sorry if this is a really stupid question but I don't know what the right course of action is here.
Thanks!
[EDIT] Q.nfcall, I don't get it
So I've been looking into Q.nfcall which allows me to use node callbacks. Bu I just don't understand exacly how this works.
Could someone give a simple example how I would go about using it for a function with several async xhr calls?
I tried this but as you can see I don't really understand what I'm doing:
var second = Q.nfcall(second);
function second (files) {
[EDIT 2]
This is the final funcction in my getitemdata function callback chain. This function basically does the same as the function 'second' but I push the result directly and then return the promise. This works as stated, but without all the additional callback data, because it does not wait for the callbacks to return with any data.
function loadData(item) {
var d = Q.defer();
db.query(
'SELECT * FROM test WHERE local_name =? ', [item],{
local_name : String,
},
function(rows) {
if (typeof rows !== 'undefined' && rows.length > 0){
list.push(d.promise);
}
}
);
});
return Q.all(list);
};
Your answer is not really clear after your second edit.
First, on your orignal question, your getItemData has no influence on the promise chain.
You could change you the function's call signature and pass your deferred promise like so.
getItemData(itemRequest, d)
and pass this deferred promises all the way to your xhrCall and resolve there.
I would re-write your whole implementation and make sure all your functions return promises instead.
Many consider deferred promises as an anti-pattern. So I use use the Promise API defined in harmony (the next javascript)
After said that, I would re-implement your original code like so (I've not tested)
var Promise = Promise || require('es6-promise').Promise // a polyfill
;
function errHandler (err){
throw err
}
function makeQuery () {
var queryStr = 'SELECT * FROM test WHERE local_name =? '
, queryOpt = {local_name: String}
;
console.log('looking for item in db', value)
return new Promise(function(resolve, reject){
db.query(queryStr, [value], queryOpt, function(rows) {
if (typeof rows !== 'undefined' && rows.length > 0){
console.log('found item!', rows[0].local_name);
resolve(rows[0]);
} else {
// note that it returns a promise now.
getItemData(value).then(resolve).catch(errHandler)
}
})
})
}
function first () {
return new Promise(function(resolve, reject){
fs.readdir(path, function(err, files){
if (err) return reject(err)
resolve(files)
})
})
}
function second (files) {
return Promise.all(files.map(function(value){
return makeQuery(value)
});
}
first()
.then(second)
.then(res.send)
.catch(errHandler)
Note that there is no done method on the Promise API.
One down side of the new Promise API is error handling. Take a look at bluebird.
It is a robust promise library which is compatible with the new promise API and has many of the Q helper functions.
As far as I can tell, you need to return a promise from getItemData. Use Q.defer() as you do in second(), and resolve it when the callbacks complete with the data. You can then push that into list.
To save code, you can use Q.nfcall to immediately call a node-style-callback function, and return a promise instead. See the example in the API docs: https://github.com/kriskowal/q/wiki/API-Reference#qnfcallfunc-args