I have a promise like below:
let promise = new Promise((resolve, reject) => {
axios.post("https://httpbin.org/post", params, header)
.then(response => {
resolve(Object.assign({}, response.data));
// resolve("aaaa");
console.log(response);
})
.catch(error => reject(error))
});
Why i need to resolve this promise with response data?
What happens if i replace resolve(Object.assign({}, response.data)); line by resolve("aaaa"); ?
Any one can help me? Thank you.
Something that's worth mentioning is axios.post() already returns a Promise so you needn't wrap it in another promise.
This will work instead:
let promise = axios.post("https://httpbin.org/post", params, header)
.then(response => {
console.log(response);
return Object.assign({}, response.data);
});
// Later on...
promise.then(data => {
console.log('Request successful:', data);
}, err => {
console.log('Request failed:', err);
});
Constructing a new Promise object is only necessary when you aren't chaining off an existing promise, like in this example:
function delay(duration) {
return new Promise(resolve => setTimeout(resolve, duration));
}
delay(1000).then(() => {
console.log('this code is delayed by 1s');
});
resolve() does exactly what the name says: It resolves the promise returning the value inside the function call.
So if you have a promise and it is resolving with resolve('aaaaa'), this means your promise will return a successful state with it's value being 'aaaaa'.
You could also reject the promise. This would mean the call you did failed at some point. Analog to resolve(), reject() accepts a parameter that should be returned by the promise.
All it will do is call the success callback resolve with the argument "aaaa" instead of its original value.
Let's say you pass the callback function console.log. If the promise resolves, i.e. is successful, then the callback will be called with the passed argument (console.log("aaaa"))
If it doesn't resolve - if it's unsuccessful - then the reject callback will be called as per your .catch() statement.
Promises have two arguments, resolve and reject, that are used to send a response back to the invoking code.
If your promise completed its code without errors, then you resolve() it, by sending back the response (it can be whatever you want) and if it fails instead, you reject() it, usually passing the error as parameter.
The parameter of the resolve function will be sent back to the invoking function, in the then callback, while the parameter of the reject function can be found in the catch callback.
For example
function myFunction(){
return new Promise((resolve, reject) => {
try{
/* Do some async calls here */
resolve(result); //Result is what you will find in "then"
}catch(e){
reject(e);
}
});
}
myFunction().then((response) => {
/* Your logic here*/
}).catch((err) => {
console.error(err);
}
You can think the resolve as a return in an asynchronous context, while the reject is similar to throwing an exception that will be caught by the invoking code.
So resolve(myVariable) will return myVariable to the code that called the promise function, while resolve('aaa') will always return "aaa" to the invoking code.
Related
fetch("https://jsonplaceholder.typicode.com/posts").then(
(response) => {
console.log(response.json()); //why the data not logged and promise is logged
}
);
but work if i writte
let response = fetch("https://jsonplaceholder.typicode.com/posts")
.then((response) => response.json())
.then((data) => console.log(data));
why the data is not logged and promise is logged in the first code?
response.json() is returning a promise, so you need to await it, either by doing what you did in the second example, or using async and await:
fetch("https://jsonplaceholder.typicode.com/posts").then(
async (response) => {
console.log(await response.json());
}
);
js fiddle: https://jsfiddle.net/hy15ve68/
This is only to demonstrate how you would get the data out of the promise (don't do it this way):
fetch("https://jsonplaceholder.typicode.com/posts").then(
(response) => {
// response.json() returns a Promise which we can call
// .then() on.
response.json().then(console.log)
}
);
The second code is actually a shortened version of:
let response = fetch("https://jsonplaceholder.typicode.com/posts")
.then((response) => {
return response.json()
})
// .then() refers to the promise returned by response.json()
.then((data) => {
return console.log(data)
});
This is the correct way of chaining Promises.
As you can see, we return the Promise returned by response.json() and then call .then() on it.
The good thing about chaining Promises is that synchronous values (like numbers, strings etc.) get wrapped in a Promise so you can still call .then() on it:
let dummy_promise = (new Promise(resolve => {
resolve(1)
}))
dummy_promise.then(value => {
console.log("im expecting 1", value)
return 2;
})
.then(value => {
console.log("im expecting 2", value)
return 3;
})
.then(value => {
console.log("im expecting 3", value)
})
.then(value => {
console.log("im expecting undefined because we haven't returned anything in the previous .then() block!", value)
})
A little background information:
You cannot expect the result of a Promise to be available immediately.
This is why you use .then() - it's a way of saying "call this function when the value IS available".
When you console.log(response.json()) you get the Promise object, but not it's resolved value.
Note: Even if the Promise itself was resolved, response.json() will continue to give you the Promise object itself.
You can still call .then() on it and your function will be called with the resolved value.
I hope this small example shows what I mean:
// returns a Promise that gets resolved to "hello!" after
// 100 ms (milliseconds)
function something() {
return new Promise((resolve) => {
setTimeout(() => {
resolve("hello!")
}, 100)
})
}
// call something() and store the promise in promise_object
let promise_object = something()
console.log("Installing .then() handlers")
// call console.log twice after promise is resolved
// (means they will be called in about 100ms - when the promise is resolved)
promise_object.then(console.log)
promise_object.then(console.log)
console.log("Installed .then() handlers")
// wait for 1 second, then print promise_object
setTimeout(() => {
console.log("1 second has passed")
// at this point the promise returned by something() surely must be
// resolved
console.log(promise_object) // Still prints Promise {} and not "hello!" - that's intended behavior
// gets called without delay because promise is already resolved!
promise_object.then(console.log)
}, 1000)
Output:
I am using tableau js api and calling worksheet.applyFilterAsync & workbook.changeParameterValueAsync methods based on certain conditions. These methods have an otherwise error handler.
I am also in between the executing flow return my custom promise like
return new Promise((resolve, reject) => {
resolve(true)
});
the issue is when i am returning promise and not changeParameterValueAsync or worksheet.applyFilterAsync i am getting an error
TypeError: undefined is not a function (near '...}).otherwise(function (err) {...')
looks like the promise i return does not have a otherwise error handler?
relevant code is as follows
const applyStep = (step) => {
if(step.step_type == 'filter') {
return worksheet.applyFilterAsync(step.name, values, 'replace');
} else if(step.step_type == 'parameter') {
return workbook.changeParameterValueAsync(`${step.name}`, value);
} else {
return new Promise((resolve, reject) => {
resolve(true)
});
}
};
const applyFilters = (counter) => {
return new Promise((resolve, reject) => {
let filter = filters[counter];
if(filter) {
applyStep(filter).then(promiseTimeout(filter.delay)).then(() => resolve(applyFilters(++counter))).otherwise(function(err) {
reject(err);
});
} else {
resolve(true);
}
});
};
I need the otherwise error handler to handle error returned by tableau api methods but it does not work in cases where i am returning my custom promise, may be because the promise i am returning does not have an otherwise error handler?
How can address this any help in fixing this will be really great, Thanks.
From the tableau docs:
otherwise(errback: Function) Promise Registers a rejection handler. Shortcut for then(null, errback).
So in your code, you could do
applyStep(filter)
.then(promiseTimeout(filter.delay))
.then(() => resolve(applyFilters(++counter)))
.then(null, function(err) {
reject(err);
});
That is instead of .otherwise(err) you can use .then(null, err).
The issue is that you are currently mixing two different types of promises. The tableau Promise and the standard JavaScript Promise. These two have different methods which currently results in issues. You can pass a tableau Promise to Promise.resolve() to convert it into a standard JavaScript Promise.
return Promise.resolve(worksheet.applyFilterAsync(step.name, values, 'replace'));
When working with the promise you now have to work with then(), catch() and finally() instead of then(), otherwise() and always().
I am trying to create a wrapper function that returns a Promise object which will resolve after an inner Promise resolves. Basically, something like this:
function wrapper() {
return new Promise((resolve, reject) => {
MyApi.asyncCall()
.then(data => {
// do this first, then resolve outer promise
resolve();
})
.catch(e => {
reject();
});
});
}
The reason I need to do this is I have an interface that accepts a promise argument, then triggers an action once that promise resolves. I need to make an async call, then do something with the response, then trigger the interface.
Edit
Explanation of purpose: I need to perform actions with the response of the inner promise BEFORE resolving the outer promise. The interface accepts an unresolved promise object, and then mounts a component when it is resolved. If I pass the inner promise it will mount before the actions on the data response are performed.
Basically — you doing it right. You are resolve \ reject promise when you need.
But you can do it easily — simply return original promise:
function wrapper() {
return MyApi.asyncCall()
}
So your returning promise, which resolves or rejectes when MyApi.asyncCall resolves or rejects.
If you need to do some staff inside you can do it inside this promise:
function wrapper() {
return MyApi.asyncCall()
.then((data) => {
doSomeOtherStaff(data)
return data
})
}
Note that if you need data outside — you have to return it from your then callback inside.
Can you explain why you need the wrapper promise exactly?
MyApi.asyncCall()
.then(data => {
// do this first, then resolve outer promise
resolve();
})
.catch(e => {
reject();
});
is a promise itself, and it should be enough to just return it.
You can use async await for the first promise and after getting data of the first promise then return the second promise :
function wrapper(){
return new Promise( async (resolve,reject)=>{
let myFirstPromise = await firestPromise();
// do your stuff here
console.log(myFirstPromise)
return resolve('Second Promise');
});
}
function firestPromise(){
return new Promise( (resolve,reject)=>{
return resolve('First Promise');
});
}
I'm struggling to handle errors with Promise.all:
return Promise.all([
this.pagination(),
this.prepareParams(this.params, this.requestData),
this.fetchRecipes(this.apiData, this.params)
])
.catch(e => console.log());
Firstly I've just tried to throw an exception in this.pagination(), it was even handled, but strangely enough the next Promises were despite executed.
pagination(): Promise<any> {
return new Promise(resolve => {
if(...) {
...
resolve();
} else {
...
throw "no more results";
}
}
Then I tried to use Promise.reject("no more results") instead, but the problem is that it ignores now somehow my catch
Uncaught (in promise): no more results
UPDATE
Just to clarify for others: My original intention was to prevent the execution of the next 2 Promises, if the first one was rejected. Mistakenly I assumed that Promise.all fulfills this requirement. Thanks to the answer of traktor53 I realised that chaining promises is a better solution.
Promise.all waits for all the promises in its argument array to be fulfilled before returning an array of results, but will reject the promise it returned as soon as any of the promises in the array become rejected ("fast rejection").
Promise.all calls then on each of the promises passed to obtain its fulfilled value or rejected reason. It does not attempt to abort other promises if one of them is rejected - there is no mechanism in Promise standards to cancel a promised operation.
If you want to continue execution of promise operations only after a preceding promise is successful, use chaining rather than promise.all, taking care that the this value is correct in promise call backs (e.g. by using arrow functions):
function objectMethod () {
return this.pagination()
.then( data=>this.prepareParams(this.params, this.requestData))
.then( data=>this.fetchRecipes(this.apiData, this.params));
}
// catch errors encountered during call:
someObject.someMethod().catch(e => console.log(e));
The callback parameter to the Promise constructor (MDN) takes two arguments, idomatically called resolve and reject, the latter of which you are missing. Instead of throwing the error, you must pass it to reject. Therefore:
pagination(): Promise<any> {
return new Promise((resolve, reject) => {
if(...) {
...
resolve();
} else {
...
reject("no more results");
}
}
Better to add
try - catch block when you call a function
else
pagination(): Promise<any> {
return new Promise((resolve, reject) => {
if(...) {
...
resolve();
} else {
...
reject("no more results");
}
}
In your function call.
pagination().then(err, value) {}
In my console.log(info), I want to get the value of "result". But when I use console.log(info), I get Promise { <pending> }:
var info=new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (body.match('success') || body.match('code="25"')) {
resolve("success");
} else {
reject(body);
}
});
}).then(result => {
return result;
}).catch(err => {
console.log("error: " + err)
});
console.log(info);
I would like to get info == result. How can I do it?
Thanks
What happens here
First some explanation of what happens here. When you do something like this:
var info = new Promise((resolve, reject) => {
// ...
}).then(result => {
// ...
}).catch(err => {
// ...
});
then what ends up as the value of the info variable is a promise. That's because you start with a promise returned by the new Promise() constructor, you invoke its .then() method which returns a second promise, and on that second promise you invoke the .catch() method which returns a third promise - and this third promise is what gets saved into the info variable.
All of those method calls return immediately before the original HTTP request is finished so when you reach the next line:
console.log(info);
it's impossible to access the value of the response from the request() call because it didn't happen yet (the request() callback hasn't been called yet at this point). The info variable has a promise which is an object that you can use to register the callbacks that you want run when the value is eventually available. When you pass it to the console.log() it prints that it's a promise.
How to get the value
Now, when you want to print the value when it's finally available then you can attach a promise resolution callback to the promise that you have e.g. with a code like this:
info.then((value) => {
// you can use the value here
console.log('Value:', value);
}).catch((err) => {
// the promise got rejected
console.log('Error:', err);
});
If you are using a relatively recent version of Node (7.0+) then you could use await if you are inside of a function declared with an async keyword, to get the resolution value of the promise like this:
(async function () {
let value = await info;
console.log(value);
})();
or shorter:
(async () => {
console.log(await info);
})();
(If you are already inside of an async function then you don't need the (async () => { ... })(); wrapper.)
How it works
What the await keyword does is it yields the promise from an implicit generator function that passes the control to the outer coroutine control code which attaches a resolution and rejection handlers to that yielded promise and starts the generator again by either returning the resolved value from the await operator or raising an exception if the promise was rejected. The generator can then continue using the return value and catching the exception, or it can let the exception bubble to the outer blocks where it can be caught or converted to a rejection of the implicit promise returned by the async function if not handled along the way.
How you can use it
It may seem complicated but from the point of view of your code it lets you do things like:
let value = await fun();
(where fun() is a function that returns a promise) and have the resolved value of the promise available in the value variable (the real value, not a promise).
Remember that the await keyword throws an exception when the promise in question gets rejected. To handle that case you can use a try/catch block:
try {
let value = await fun();
// promise got resolved, you have value here:
console.log('Value:', value);
} catch (error) {
// promise got rejected, you have error here:
console.log('Error:', error);
}
which is equivalent of this code without the new syntax:
fun().then((value) => {
// promise got resolved, you have value here:
console.log('Value:', value);
}).catch((error) => {
// promise got rejected, you have error here:
console.log('Error:', error);
});
with the main difference being the variable scoping when you await on multiple promises in a single try block as opposed to using multiple chained .then() handlers, each returning a new promise.
Your code looked like it used await but it didn't
I added the example of how to fix your code with await because you wrote your code as if this:
var info = new Promise(...);
// here the 'info' variable is set to a promise
was really this:
var info = await new Promise(...);
// here the 'info' variable is set to the value
// that the promise eventually resolves to
More info
For more info, see:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
Node support
For support of that syntax in Node versions, see:
http://node.green/#ES2017-features-async-functions
In places where you don't have native support for async and await you can use Babel:
https://babeljs.io/docs/plugins/transform-async-to-generator/
or with a slightly different syntax a generator based approach like in co or Bluebird coroutines:
https://www.npmjs.com/package/co
http://bluebirdjs.com/docs/api/promise.coroutine.html
In your code, info is a promise. Thus, you don't compare info to anything. To get access to the result in a promise, you use .then() on the promise as in:
info.then(result => {
// test result here
}).catch(err => {
// handle error here
});
In addition, your .catch() handler is "eating" the error after logging it. If you don't rethrow the error or return a rejected promise from a .catch() handler, then the error is considered "handled" and the promise state changes to fulfilled.
So, you can do this:
let info = new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (body.match('success') || body.match('code="25"')) {
resolve("success");
} else {
reject(body);
}
});
}).catch(err => {
console.log("error: " + err);
// rethrow error so promise stays rejected
throw err;
});
info.then(result => {
// test result here
}).catch(err => {
// handle error here
});