I am trying to write logic in JS to stop function execution abruptly (without executing further) when in call sequence. Check below code. Why isn't stopping after second call?
function myprom (value) {
return new Promise (function (resolve, reject) {
resolve("I Promise " + value)
})
}
function myfunc (value) {
console.log("Starting in " + value)
}
function terminate() {
setTimeout(() => console.log("Edning"), 1)
}
function dummy() {
console.log("I am not supposed to print anything")
}
async function call() {
await myprom("to end without showing next line")
.then(result => {
myfunc(1) // Call # 1
console.log(result) // Call # 2
terminate() // Call # 3
dummy(1) // Call # 4
terminate() // Call # 5
})
.catch(err => {
console.log(err)
})
}
call()
Below is the actual output of my code.
Starting in 1
I Promise to end without showing next line
I am not supposed to print anything
Ending
Ending
What is expected is,
Starting in 1
I Promise to end without showing next line
Ending
In general. how to stop js execution abruptly inside .then object?
When you call this terminate() which is this:
function terminate() {
setTimeout(() => console.log("Edning"), 1)
}
The setTimeout() pushes it's callback to a future cycle of the event loop and EVERYTHING else in the current cycle of the event loop runs before it. Only when the current chain of code has finished and control has returned back to the event loop will the setTimeout() get a chance to run its callback.
So, here's the sequence of what happens in your code:
call() is executed.
myprom() is executed. That resolves its promise immediately so it will schedule it's .then() handlers to run as soon as control returns back to the event loop.
.then() and .catch() run. All they do at this point is register some callbacks to be called later when the promise is ready to execute them.
Your async function returns and control goes back to the event loop.
The already resolved promise is first in line in the event loop so it gets control and executes it's .then() handler.
myfunc(1) runs and that outputs Starting in 1
console.log(result) runs and that outputs I Promise to end without showing next line
terminate() runs and that sets a timer for 1ms from now. That function returns and the timer is schedule to run on a future tick of the event loop when 1ms has passed.
dummy(1) is called and that outputs I am not supposed to print anything.
terminate() is called again and that again schedules another timer to run in 1ms on a future tick of the event loop.
The await processes the promise and resolves the promise that the async function call() returns. The await does nothing useful here and there's nothing listening for the promise that call() returns either.
Control is returned back to the event loop.
The first timer you set with the first call to terminate() gets to run and it outputs. That returns control back to the event loop.
The second timer you set with the second call to terminate() gets to run and it puts. That returns control back to the event loop and everything associated with this code is done.
In general. how to stop js execution abruptly inside .then object?
If what you're asking is how you skip the other functions you call all in a row, then you would typically use conditionals to branch of return early out of the .then() callback. For example, you could do this:
async function call() {
await myprom("to end without showing next line")
.then(result => {
myfunc(1) // Call # 1
console.log(result) // Call # 2
if (result === "I Promise to end without showing next line") {
// skip the rest of the code in this callback
return;
}
terminate() // Call # 3
dummy(1) // Call # 4
terminate() // Call # 5
})
.catch(err => {
console.log(err)
})
}
call()
Since you're in a .then() handler, you could also so a throw someError and that would abruptly stop the .then() handler just like throwing any exception aborts the execution of the current function. Because this is in a .then() handler that exception will be immediately caught and will then execute the .catch() handler and pass it the exception you threw. This wouldn't typically be used for a normal execution path because this more typically indicates some error condition. A normal execution path would more likely catch the condition locally and use branching or if/else logic or something like that to decide what code in the function executes next.
Note, if you've already started some timers, then to keep them from firing, you would have to save the timerID that setTimeout() returned and use clearTimeout() on that timerID to cancel the timer.
If you really want abrupt stopping to stop your whole process, then in node.js, you can also call process.exit().
It's unclear why you thought the output from dummy(1) and the second call to terminate() would not show in the output? You called dummy(1). Nothing in the terminate() function causes Javascript to skip the rest of the code in the .then() handler. So, it continues and executes both dummy(1) and the second terminate() and thus you see the output from both.
Instead of calling terminate you could use return. That would solve your purpose.
The function terminate does not stop the execution of the function but instead schedules a function to run later with a timeout of at least 1 second. So, the function should instead be called delay. I have added a Promise based implementation of the same:
function delay(time = 1) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Ending');
resolve();
}, time);
})
}
A function returning a scalar value can be awaited. So, there is no need to wrap myProm using the Promise constructor. Assuming that myprom is a real async operation instead of a function returning a string, of course.
function myprom (value) {
return `I Promise ${value}`;
}
When using async functions, the callback with .then and .catch is not necessary.
async function call() {
try {
const result = await myprom("to end without showing next line")
console.log(result)
myfunc(1)
} catch (e) {
console.error(e);
}
}
The existing code snippet with the changes would look like this:
// scalar values can be resolved too
function myprom (value) {
return `I Promise ${value}`;
}
function myfunc (value) {
console.log("Starting in " + value)
}
function delay(time = 1) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Ending');
resolve();
}, time);
})
}
function dummy() {
console.log("I am not supposed to print anything")
}
async function call() {
try {
const result = await myprom("to end without showing next line")
console.log(result)
myfunc(1)
await delay();
dummy(1);
await delay();
} catch (e) {
console.error(e);
}
return undefined;
}
call();
However, as explained this will not stop the flow of execution:
myprom runs
result is printed
myFunc executes
after a delay of 1 second, a message of Ending prints (because the event loop is not blocked by many async operations)
dummy executes
after a delay of 1 second, a message of Ending prints
the function returns a Promise that resolves to a value of undefined.
Instead of using delay, we can use return when we need to terminate the execution of the function:
function myprom(value) {
return `I Promise ${value}`;
}
function myfunc(value) {
console.log("Starting in " + value)
}
async function call() {
try {
const result = await myprom("to end without showing next line")
console.log(result)
myfunc(1);
return
} catch (e) {
console.error(e);
}
}
call();
Related
Hello I need to call a REST function with an ID, that returns a promise in React.js. This function will at some point contain a certain value in its response when called . Until another service has processed an initial request this value will be null.
This is what I have done so far:
while(myVariable){
myfunction(myID).then( (response) => {
if(response['value'] != null
myVariable = false;
}
});
}
The problem with this code is that the while loop is called as fast as possible and thus completely utilises the computer. So I need a function that allows me to poll for a result by an ID until the response of one of the function calls contains a valid response.
I have tried the following method but without success, because I don't have a fixed number of runs:
Wait promise inside for loop
Thanks in regards.
As you state, the problem is that the while loop runs eagerly, not waiting for each promise to resolve.
One way to solve that is to use recursion. Recursion gives you more control over when exactly you want to 'loop' next:
let getValue = () => {
myFunction(myID).then(response => {
if (response['value'] === null) {
setTimeout(getValue);
} else {
// here you know the other service has processed the initial request
}
});
};
First I wrapped the whole thing in a function called getValue. Note that this function is only called again after the promise resolves. (The call to setTimeout is a trick to use recursion without consuming the stack.) If this still runs too quickly, pass an additional parameter of 100 or so to the setTimeout invocation.
Alternatively, you may be able to use async/await similarly to the link you shared. I'm no expert on async/await but it should work the same with while loops as with for loops, judging by this and this.
You can use the async function with await.
I also use a delay function to delay each call to the myfunction().
While you get a response, you can break the while loop.
const delay = ms => new Promise((resolve, reject) => setTimeout(resolve, ms));
async function main() {
const myID = 1;
let response;
while (true) {
response = await myfunction(myID);
if (response["value"] != null) {
break;
}
await delay(5000);
}
//do Something once you get the response here below:
}
main();
I have the following code:
const doWorkPromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('#2 (async call)');
}, 0);
resolve('#3 (async call?)');
console.log('#1 (sync call)');
});
doWorkPromise.then((result) => {
console.log('Success!', result);
}).catch((error) => {
console.log('Error!', error);
});
The output is:
#1 (sync call)
Success! #3 (async call?)
#2 (async call)
I know that sync code lands on the call stack and the async code registers event-callback pair at the Node APIs, where the callback is moved to the callback queue after the event. The event loop is then going to take elements out of the callback queue only when the call stack is empty. Therefore, I expected to have the sync code executed first and then the async one in order, because the timeouts are 0s, like:
#1 (sync call)
#2 (async call)
Success! #3 (async call?)
Can someone please explain why resolve is executed before '#2 (async call)'?
reject is never executed.
resolved is executed before #2 because:
setTimeout puts a function on the time out queue
resolve resolves the promise
console.log logs #1
The function finished
doWorkPromise.then assigns a function to run when the promise resolves
The promise is already resolved so that function is executed
After the minimum timeout time passes the function passed to setTimeout is called and logs #2
Your code executes the following synchronously:
resolve('#3 (async call?)');
...so that promise gets immediately in a resolved state. The fact that you have started a timer, as no bearing on the promise... it is unrelated.
So the then callback on that promise will be triggered on the next processing of the job queue, and so you'll see "Success", right after the execution of the main, synchronous code has completed.
Somewhat later (yes, even setTimeout(..., 0) will introduce a small delay), the timer will expire, but that event has nothing to do with any promise.
The common pattern
When you create a promise with new Promise and want it to resolve some time later, then you could indeed use setTimeout, but then the idea is to call resolve only when that timer has expired. Otherwise the timer does not do anything that serves the promise:
setTimeout(() => {
resolve();
}, 0);
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.
I would like to compose two functions which return Promises into a function which returns a Promise.
I really want to do this for asynchronous system calls, but to simplify things, for now I'm playing with Promises wrapped around setTimeout. Most of the system calls can be sent out and returned in any order, but in a few instances, data from one system call is needed to create a second system call.
In the enclosed example, I want to send out alerts with an interval of 5 seconds, then 3 seconds, then 10 seconds. When I run the code, things run in the wrong order.
I commented out code where I was able to run the two calls chained with ".then". The commented out code works as desired. But I haven't yet figured out how to put that into a function which returns a promise, and still have it work.
I'm interested in doing this using plain JavaScript only. After I understand how to do that, I'll look at answers which do the same using a library.
jsfiddle
// Returns a Promise.
// I purposely chose not to use the callback function inside setTimeout in order to demonstrate
// how to combine functions which return Promises, and normal functions which don't.
function sleep(delay, callbackFunction) {
return new Promise(function(resolve) {
setTimeout(resolve.bind(null, callbackFunction), delay)
});
}
// Normal function, does not return a promise.
const myPrint = (message, value) => {
alert(message + " " + value);
};
// A function combining a promise and then a normal function.
// Returns a Promise.
const sleepPrint = (delay) => {
return sleep(delay)
.then(() => {
myPrint("sleepPrint()", delay);
});
};
// A function combining two functions which return promises.
// Returns a Promise.
const sleepPrintSleepPrint = (delay1, delay2) => {
return sleepPrint(delay1)
.then(sleepPrint(delay2));
};
alert("Begin");
/*
// Run a Pomise function, then a normal function.
const delay = 4000;
sleep(delay)
.then(() => {
myPrint("init", delay);
});
*/
const firstDelay = 5000;
const secondDelay = 3000;
/*
// Call sleepPrint() which runs a Promise function then a normal function.
// After all that finishes, call another Promise function, than another normal function.
// This code works as desired, but the code at the bottom doesn't!
sleepPrint(firstDelay)
.then(() => {
return sleep(secondDelay)
})
.then(() => {
myPrint("After sleepPrint() and sleep()", secondDelay);
});
*/
// Comine two calls to sleepPrint() into a new functiion which returns a Promise, sleepPrintsleepPrint().
// After all that finishes, call another Promise function, than another normal function.
// I want this to have 5 second delay and then a 3 second delay, but they are not running in that order.
const thirdDelay = 10000;
sleepPrintSleepPrint(firstDelay, secondDelay)
.then(() => {
return sleep(thirdDelay)
})
.then(() => {
myPrint("After sleepPrintSleepPrint()", thirdDelay);
});
Remember how functions work (in any programming language). This:
const sleepPrintSleepPrint = (delay1, delay2) => {
return sleepPrint(delay1)
.then(sleepPrint(delay2));
};
Is the same as this:
const sleepPrintSleepPrint = (delay1, delay2) => {
var x = sleepPrint(delay2);
return sleepPrint(delay1)
.then(x);
};
What you are doing is calling both functions simultaneously. What I think you intend is to call the second function once then resolves. So you need to do this:
const sleepPrintSleepPrint = (delay1, delay2) => {
return sleepPrint(delay1)
.then(function(){return sleepPrint(delay2)});
};
Or if you prefer arrow function syntax:
const sleepPrintSleepPrint = (delay1, delay2) => {
return sleepPrint(delay1)
.then(() => sleepPrint(delay2));
};
#slebetman supplied the correct code, and he explained the issue and the fix correctly at a high level. This is my understanding of his answer in more detail. This should be a comment to his answer, but it's too big.
The JavaScript interpreter makes two passes through code which contains chained ".then"s.
The first pass happens right away without any waiting. The interpreter looks at the argument(s) to .then, and does something different if it sees a function or an expression. Functions are placed onto the call stack, and associated with a promise. Expressions are evaluated, and if the completion value is a function, the function is placed onto the call stack, and associated with a promise.
In the second pass, after a promise has been resolved, the associated function from the call stack is evaluated.
In production code, chained .then's should always follow a specific pattern. The pattern is that the argument to ".then" is one function which returns a second callback function. In the first pass, nothing very interesting happens, the first function is executed, and the return value is the second callback function. The second callback function is placed onto the call stack and associated with a promise. In the second pass, after the associated promise has been resolved, the second callback function is executed.
But in this example, I am breaking the pattern in order to learn and demonstrate how chained .then's work.
Below is an example which does not use the pattern, and exposes the two pass behavior.
This is talking about the two arguments to .then, the success callback function, and the failure callback function.
"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 you give a function to ".then", then in the first pass, the function is placed on the call stack, but nothing else happens, and in the second pass, the function is executed.
But if you give an expression to ".then", then in the first pass, the expression is evaluated. If the completion value is a function, it is placed onto the call stack, and executed in the second pass. If the completion value is not a function, in the second pass, no further action is taken, and no error is generated.
First Pass (The JavaScript interpreter runs these things immediateley.)
Kick off sleepPrint(firstDelay). Let it run in the background.
Immediately go to the next ".then".
Print the first message. Put nothing on the call stack.
Immediately go to the next ".then".
Put the function () => sleepPrint(secondDelay) onto the call stack, and associate it with the preceding promise.
Immediately go to the next ".then".
Print the second message. Put nothing on the call stack.
Second Pass (The JavaScript interpreter runs each of these steps from the call stack much later, after the corresponding promise has been resolved.)
Wait until sleepPrint(firstDelay) prints the third message, and is resolved, then go to the next item on the call stack.
There's nothing on the call stack for this slot. There's no promise to resolve, so go to the next item on the call stack. No error is generated.
Execute function () => sleepPrint(secondDelay) which prints the fourth message. Wait for the promise to be resolved, then go to the next item on the call stack.
There's nothing on the call stack for this slot. There's no promise to resolve. No error is generated.
jsFiddle
// Returns a Promise.
// I purposely chose not to use the callback function inside setTimeout in order to demonstrate
// how to combine functions which return Promises, and normal functions which don't.
function sleep(delay, callbackFunction) {
return new Promise(function(resolve) {
setTimeout(resolve.bind(null, callbackFunction), delay)
});
}
// Normal function, does not return a promise.
const myPrint = (message, value) => {
alert(message + " " + value);
};
// A function combining a promise and then a normal function.
// Returns a Promise.
const sleepPrint = (delay) => {
return sleep(delay)
.then(() => {
myPrint("sleepPrint()", delay);
});
};
alert("Begin");
const firstDelay = 5000;
const secondDelay = 3000;
// This message is printed third.
sleepPrint(firstDelay)
.then(
myPrint("This message is printed first", 0)
)
.then(
// This message is printed fourth.
() => {sleepPrint(secondDelay)}
)
.then(
myPrint("This message is printed second", 0)
);
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;
};