So I'm currently learning about promises in JavaScript, and I tried making my first promise and realized that it ran the setTimeout() even if I didn't call the promise to begin with, just by defining it, it ran by itself. This being postLogin.
const postLogin = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Token: 1234")
}, 2000);
});
^ This logs out "Token: 1234" without calling postLogin.then()
Where as this doesn't run until I call postLogin1.then(token => {console.log(token)});
const postLogin1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Token1: 1234");
}, 2000);
});
postLogin1.then(token => {console.log(token)});
Why is it that if I don't add "resolve" it runs the code without invoking it?
Promise constructors call the function you pass to them immediately. This is the case in both your examples.
If you have console.log inside that function, then it will call console.log. If you don't, then it won't. That's the key difference between the examples.
The then method just adds an event handler that will be called when the promise is resolved (or immediately if it has already been resolved).
If you have console.log in the then handler, then it will be called then the function resolves.
If you don't ever call resolve then it will never resolve. The function you pass to it is still called.
Related
I'm learning Javascript async programming and Promise. I have the following code.
let promiseTest = () => new Promise((resolve, reject) => {
console.log("Inside Promise");
resolve('Promise is resolved');
});
console.log("Before Promise");
promiseTest().then((data) => { console.log(data); });
console.log("After Promise");
I have the function "promiseTest". I want to execute that asynchronously. In real world scenario, it could be a function that fetch the web service or query the database. I was expecting to have the following result from the code.
Before Promise
After Promise
Inside Promise
Promise is resolved
I was expecting that "console.log(" Inside Promise") " will be executed asynchronously since it is inside the Promise function. But the actual result is
Before Promise
Inside Promise
After Promise
Promise is resolved
As you see tin the actual result, Inside Promise is executed synchronously and blocking the main thread. Only the code inside "resolve" is asynchronous. Maybe, my current understanding of javascript Promise is incorrect. How do I modify my existing code to make sure the whole function " promiseTest " is executed asynchronously without blocking the main thread.
The executor function is executed synchronously. Promise doesn't make any code asynchronous; its just a mechanism to get notified when something, that is already asynchronous, has completed.
If you want to make a API call, that is already asynchronous and if you use the fetch API, then you don't need the promise constructor because fetch(...) already returns a promise.
Only the code inside "resolve" is asynchronous
In your code, resolve() function is also called synchronously; only the callback function of promiseTest().then(..) is invoked asynchronously.
How do I modify my existing code to make sure the whole function
"promiseTest" is executed asynchronously without blocking the main
thread.
You will have to use another thread. Even if you delay the execution of the promiseTest function using setTimeout, once it is pushed in the call stack, it will execute synchronously. Nothing else will execute when the delayed promiseTest function is being executed.
If delaying the execution is what you want, just wrap the promiseTest function call in setTimeout.
I'd suggest using setTimeout for your promiseTest function, this will give you the expected result.
setTimeout sets a timer which executes a function once the timer expires.
As you can see "After Promise" will be logged before "Promise is resolved", this is entirely expected, since the promise will take some time (in this case 1000 milliseconds) to resolve.
let promiseTest = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Inside Promise");
resolve('Promise is resolved');
}, 1000)
});
console.log("Before Promise");
promiseTest().then((data) => { console.log(data); });
console.log("After Promise");
My goal is to generate an array of Promises dynamically (by using Array.map()), and execute them at a posterior time.
export const ExecuteReader = async () => {
let strAll = [1, 2].map((num) => testingFunction (num))
//await Promise.all(strAll)
}
export const testingFunction = (num) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('I have been called');
resolve(1)
}, 1000)
})
}
ExecuteReader function is called by a "OnPress" event. (React-Native Touchable opacity.)
<TouchableOpacity
onPress={async () => {
await ExecuteReader().catch(err => console.log(err));
}}>
<Text>Click Me</Text>
</TouchableOpacity>
To my understanding, the strAll Promise array should not execute its underlying functions, until it has been awaited ("Promise.All")
Im my case, it seems that the "testingFunction" prints out to console, while the "map" is iterating.
Your help is appreciated.
To my understanding, the strAll Promise array should not execute its underlying functions, until it has been awaited ("Promise.All")
That's incorrect, but you're not alone — it's a common misunderstanding. :-) Promises don't do anything, they're a way to observe and report on the completion of something else. When you call new Promise, the function you pass into it (the promise executor) is called right away, synchronously, to start the operation. Observing the promise via then, catch, etc. (directly or indirectly through Promise.all) doesn't make anything happen, it just hooks up handlers that will be called when whatever is already happening finishes (or if it's already done, will be called almost immediately [but still asynchronously]).
If you want to start those processes later, you need to delay your calls to testingFunction, since calling it starts the timer immediately.
I have some websocket code in JS. I have a message-handling loop like this:
socket.addEventListener('message', function (event) {
payload = JSON.parse(event.data)
method = payload.method
// Dispatch messages
if (method == 'cmd1') {
handle_cmd1(payload); // trigger event/semaphore here to wait up waiter
}
else if (method == 'cmd2') { ... }
});
And elsewhere, I have a button callback like this:
$('#my-button').change(function() {
handle_button();
});
async function handle_button() {
send_msg('msg1', 'hi');
// wait for server to reply with cmd1
cmd1_data = await something(); // what?
alert(`cmd1 data: $(cmd1_data)`);
}
The idea is that the button sends 'msg1' and the server is supposed to reply with 'cmd1' and some info. I want to wait for that reply and then do some more stuff.
So my question is how to interlock these? In C++ I'd use a semaphore. I'd rather not spin-loop; is there something in Javascript/JQuery I can use to trigger and then wait for a user-defined event like this? I'm sort of new to JS, and very new to JS async/await.
EDIT: I've made a simple jsfiddle to show what I'm after.
http://jsfiddle.net/xpvt214o/484700/
Now that I understand how promises in Javascript work, here's a working example of a promise that can get woken up from anywhere by calling a function:
wakeup = null;
// returns a promise that will be resolved by calling wakeup()
// (could be a list of these or whatever, this is just a simple demo)
function wakeable() {
return new Promise( (resolve) => {
wakeup = () => { resolve(true); }
});
}
// demo of waiting and getting woken up:
async function handle_event() {
while (true) {
console.log("waiting...")
await wakeable(); // returns to event loop here
console.log("handle event woke up!");
}
}
handle_event(); // start in "background"
wakeup(); // wake it up
setTimeout(_ => { wakeup(); }, 500); // wake it up again after a delay
What's happening here is that when you call wakeable(), it returns a promise. That promise is constructed with an anonymous function (the one taking resolve as arg); the promise constructor synchronously calls that function, passing it the promise's resolve method. In our case, the function sets wakeup to another anonymous function that calls the original resolve; it's a closure so it has access to that resolve function even when it's called later. Then it returns the new promise.
In this demo, we then await on that promise; that puts the pending promise on a queue, saves the current function state, and returns, like a generator calling yield.
A promise is resolved when its resolve function is called; in this case calling wakeup() calls the promise's internal resolve() method, which triggers any .then methods on the next tick of the Javascript event loop (using the promise queue mentioned above). Here we use await, but .then(...) would work the same way'
So there's no magic; I/O and timeout promises work the same way. They keep a private registry of functions to call when the I/O event or timeout happens, and those functions call the promise's resolve() which triggers the .then() or satisfies the await.
By the way, unlike async in python, leaving a pending promise "open" when the process exits is perfectly fine in Javascript, and in fact this demo does that. It exits when there's no more code to run; the fact that the while loop is still "awaiting" doesn't keep the process running, because it's really just some closures stored in a queue. The event loop is empty, so the process exits (assuming it's in node.js -- in a browser it just goes back to waiting for events).
something() should be a method that returns a promise() or should be another method that is also notated with async.
function something(){
return new Promise(resolve,reject) {
//... call your database
// then
resolve(theResult)
// or
reject(theError)
}
}
The async and await for the most part are really just wrappers around promises. The await returns when the promise calls resolve, and throws an exception when the promise calls reject.
Your async function can return another promise; If it returns another value, it gets turned into a resolved promise with that value.
This question already has answers here:
What is the difference between a function call and function reference?
(6 answers)
Closed 1 year ago.
Is there any difference in efficiency?
Will the behavior be any different if a setTimeout is used instead of console.log()
You can basically do these three things
.then(console.log())
This calls the console.log immediately, without waiting until the promise is resolved, so it is not probably something that you would want to do.
.then(console.log)
This executes the console.log only after the promise has successfully resolved (requires one function call) and implicitly pass the result of the promise to to the console.log function.
.then(() => console.log())
Same as before, requires 2 function calls but you can easily pass some other arguments to it.
To pass additional argument to the console.log in the second case, you need to use Function.prototype.bind method.
const promise = new Promise((resolve, reject) => {
resolve('');
});
promise.then(console.log.bind(console, 'new arg'));
And to see all the three cases mentioned above in action
const promise1 = new Promise((resolve, reject) => {
resolve('promise 1');
});
promise1.then(console.log());
const promise2 = new Promise((resolve, reject) => {
resolve('promise 2');
});
promise2.then(console.log);
const promise3 = new Promise((resolve, reject) => {
resolve('promise 3');
});
promise3.then(v => console.log(v));
In the first case, console.log didn't receive and arguments. In the second case, the console.log received value from promise implicitly and in the third case it received the same value but explicitly.
In this scenario, the only difference in performance between the second and third case is that the third case performed one more function call (which is something that we don't really have to worry about).
I am trying to create a JS function that reads a file from storage, writes its content to the database and pushes a result message to a queue. Reading and db processing are ok but nothing happens when writing to the queue.
The code is like:
process(file)
.then(() => {
context.bindings.outQueue = { file };
return context.log('File processing completed successfully');
})
.catch(err => context.log.error(err));
If I use context.done() instead, I get the following error:
Error: Choose either to return a promise or call 'done'. Do not use both in your script.
In either case no message is written to the queue.
What's wrong?
There are a couple of things that are most likely causing you issues. First, you should be returning within the main scope of the function. Not returning will cause your Function App to hang, which is probably why you tried adding context.done(). Second, you should not call context.done() when it could return prematurely. The error message you saw is trying to prevent you from doing so. Third, you should be returning your chained promise instead of calling context.done()`. This is what will let you write to the queue correctly.
To the first point: I think you're assuming that returning inside of .then(() => { ... }); is returning for the larger-scoped function. Remember that the lambda function passed into the .then() method is just returning a fulfillment value, which is used in order to pass the result of one promise to another promise (docs here). As a side-note, I'd suggest against returning context.log('File processing completed successfully'); (just call it, don't return it), as this is the same as returning void but leads to more confusing code.
To the second point: Calling context.done() inside of .then(() => { ... }); is calling a method to indicate that the main function from a fork'd asynchronous function. This is dangerous because theoretically, at any point after .then(() => { ... }); is defined, the main function code could be killed by that call to context.done().
To the third point: If you just call context.done() in the scope of the main function instead of returning the promise, you will have the opposite problem of point #2 (the main code will exit and stop execution of the fork'd asynchronous task before the asynchronous code has completed).
Here's an example of a simple JS function that waits on a promise and writes to a queue:
Example:
module.exports = function (context, req) {
context.log("Starting function");
// Mock Promise
let doWork = new Promise(
(resolve, reject) => {
setTimeout(resolve, 100, 'foo');
console.log("Work in promise");
}
);
doWork.then(() => {
context.log("Work AFTER promise");
context.bindings.queue1= "Queue message";
context.log("Message queued!");
}).catch(err => context.log.error(err));
// This is the correct scope to return promise
return doWork;
};