promise not work as expected misunderstanding? - javascript

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:

Related

javascript promise chain with fetch not in sequence

I want to dynamically build a promise chain, that should do things in the background. Mainly it should do some output on the web page.
That works until I put promises from fetch into the chain. Those promises are not executed in the expected sequence.
The following example shows how the chain is build:
var chain = Promise.resolve();
for(var i = 0; i < actions.length; ++i)
chain = actions[i].extendChain(chain);
function actionExample(chain) {
return chain.then(...);
}
That works with direct output:
function actionOutput(chain) {
return chain.then(new Promise(resolve => {
print('text');
resolve();
}));
}
But fetch or is not in sequence:
function actionLoad(chain) {
const url = '...';
return chain.then(new Promise(() => print('run action load\n')))
.then(() => fetch(url))
.then((response) => response.json())
.then(processResponse)
.then(requestOutput)
.then(receiveOutput);
}
The function requestOutput also contains a fetch, but already the call of processResponse is delayed.
What can I change so that all steps are executed in the wanted sequence?
There's absolutely no reason to create new promises here. Passing a Promise instance to .then() is also incorrect as it requires one or two functions.
The .then() method always returns a new promise that resolves with the return value of the function provided
function actionOutput(chain) {
return chain.then(() => print('text'));
}
function actionLoad(chain) {
const url = '...';
return chain
.then(() => print('run action load\n')) // resolves with return value of
// `print()`, probably `undefined`
.then(() => fetch(url))
.then((response) => response.ok ? response.json() : Promise.reject(res))
.then(processResponse)
.then(requestOutput)
.then(receiveOutput);
}

Why i need to resolve a response in promise

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.

Ionic function return value in object t and value stored in __zone_symbol__value:

in following code, I want to return the value but it returns object:
code :
console.log(count(id));
count(id,url){
return new Promise(resolve =>
this.http.get(url)
.map(res => res.json())
.subscribe(data => {
console.log(data.count);// it shows 3 and is correct
resolve(data.count);
}));
}
output of console.log(count(id)); is:
{__zone_symbol__state: null, __zone_symbol__value: Array(0)}
__zone_symbol__state:true
__zone_symbol__value:3
A Promise is an object that represents the eventual completion or failure of an operation.
It does not return the value of the function right away, it will return the value when resolve is called.
So in the following example:
function wait(ms) {
return new Promise((resolve) => {
setTimeout(() => resolve(100), ms);
});
}
If you do console.log(wait(1000)); it will log the Promise, the object that the function is returning. To get the value you want you have to wait for the Promise to execute, you can do that in two ways:
Modern JavaScript (async/await)
const result = await wait(1000);
console.log(result); // 100
Using then
wait(1000).then((result) => console.log(result));
See also
Promise
async function
await

can I control the way a promise returned by a then() method resolves

Given I create myPromise.
It returns another promise when it resolves.
let myPromise = new Promise((resolve: Function, reject: Function) => {
setTimeout(() => {
resolve('my promise resolved after 2 seconds');
}, 2000);
})
myPromise.then(value => {
console.log(value);
}).then((value) => {
// how can I make the promise returned by myPromise.then()
//resolve in a specific way ?
})
How can I control the way the promise returned by myPromise.then() resolves ?
Inside a .then() handler, you have three choices that all influence the promise returned by that .then() call (I'll refer to it as the "parent" promise).
Return a value. When you return a value from the .then() handler, that value becomes the resolved value of the promise that was returned when .then() was originally called.
Return a promise. When you return a promise from the .then() handler, it is chained to the parent promise and the parent promise will "follow" the new promise (resolve/value, reject/reason).
Throw an exception. This will cause the parent promise to be rejected and the exception becomes the reject reason.
If you return nothing from the .then() handler that is the same as return undefined so it just sets the resolved value to undefined (same as returning a value of undefined).
This structure you show:
myPromise.then(value => {
console.log(value);
}).then((value) => {
// how can I make the promise returned by myPromise.then()
//resolve in a specific way ?
});
is troublesome because the first .then() handler returns nothing. That is the same as returning undefined and thus the second value is always undefined and thus not useful. If you had some actual reason for the first .then() handler, you could keep the desired value by returning it like this:
myPromise.then(value => {
console.log(value);
return value;
}).then((value) => {
// how can I make the promise returned by myPromise.then()
//resolve in a specific way ?
});
If you don't need to do some other async operation, just return the value:
myPromise.then(value => {
return value;
}).then((value) => {
// ...
})
But I'm not sure why you'd do this, considering you could just remove the first .then and do everything in the second .then.
If you have to do another async operation, you can return a new promise and resolve it when you need to:
myPromise.then(value => {
// Do some other async operation. I am explicitly creating the promise
// here inline to be clear. In real code, you'd probably want to wrap this
// in another function.
return new Promise((resolve: Function, reject: Function) => {
resolve(value);
});
}).then((value) => {
// ...
})

I can't get the value of "result" in Node.js

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
});

Categories

Resources