I'm working on a way to chain a set of 3 ajax calls per variable against an array of data with some delay in between.
Taking into account this answer.
I'm trying to update the code to achieve the following:
Add a delay in the b() and c() function
Pass a variable from a() to b() and from b() to c()
Is there a way I can pass a variable a() would generate to b() without using global variables? If not that's fine, I'd just like to know.
And how exactly can I get b() to be delayed for several seconds before processing c()? I would assume adding in a setTimeout would work as it's waiting for the promise before it starts c(), but this is not the case.
jsfiddle
function a(user, pass) {
return $.post('/echo/json/', {}, function(re){
console.log(1);
});
}
function b() {
setTimeout(function() {
return $.post('/echo/json/', {}, function(re){
console.log(2);
});
}, 3000);
}
function c() {
console.log(3);
}
var data = [{u: 'au', p: 'ap'}, {u: 'bu', p: 'bp'}];
var counter = 0;
function main() {
if(counter < data.length) {
$.when(a(data[counter].u, data[counter].p).then(b).then(c)).done(function(){
counter++;
main();
})
}
}
main();
To ensure that c() isn't executed until after the timeout code has been called, create your own promise and return it from the b() function. You should wrap the setTimeout function in this promise, and call the resolve(res) method to notify the .then() functions watching the promise, passing an object representing the data or body of the response.
function b(dataFromA) {
return new Promise((resolve, reject) => {
setTimeout(function() {
return $.post('/echo/json/', {}, res => {
let dataToB = res;
console.log(2);
resolve(dataToB);
});
}, 3000);
});
}
Note that b() now accepts data that can be passed from the response of the a() promise. You can manipulate this data inside the b(res) function or in the promiseFromA.then(res => { // ... Your promise callback code }); before calling b(res).
setTimeout as used in function b is not a promise. i will find some docs to site and post shortly but here is what i see.
to use a promise you need to call a promise method, setTimeout is not a promise. it is only a delay. it has to do with the event loop in javascript or in the javascript runtime to be more correct. there is some good stuff over here --> https://github.com/getify/You-Dont-Know-JS/tree/master/async%20%26%20performance
also .then only works to resolve a promise
getify really breaks it down but i would start with the javascript event loop
Related
I have two functions. First contains jQuery.get().done() and it's return value is inside done() callback function, as showed below. (I have no idea if using jQuery matters here)
I may not be understanding something, but my functions looks similar to those in first w3 example: https://www.w3schools.com/js/js_async.asp
async function A(){
jQuery.get("example.com").done(function(result){
if (result.indexOf("Example")){
console.log("sucess");
return 1;
} else {
console.log("Fail");
return -1;
}
})
}
function B(){
A().then(function(result){
console.log("Res:" + result);
})
}
B();
But the output is:
Res:undefined
// here some time passes for A() to complete.
succes
So I can't understand why .then() doesn't wait for function A() to complete and resolve promise, but instead it acts immediately while result is not defined yet ?
This is much better written using actual promises (which jQuery supports) and await as follows:
async function A() {
const result = await jQuery.get("example.com");
if (result.indexOf("Example") !== -1) {
console.log("sucess");
return 1;
} else {
console.log("Fail");
return -1;
}
}
Notes:
Stop using jQuery's .done(). It's non-standard. Use .then() or await.
Don't mix await with .done() or with .then(). Use one model or the other.
There's no need for the res intermediate variable. When you get rid of the .done(), you can just return the value directly.
Note, .indexOf() does not return a boolean. It returns -1 if not found and an index of the position if found. Best not to treat its return value as a boolean.
This isn't really a jQuery thing in particular. It's just async JS in general. I'm not sure you really need the .done() part at all since you're using promises.
But anyway, you have two basic problems.
You need to return something inside of function A, not inside .done(). So you can return jQuery.get().
In function B, you want to wait for function A to complete before hitting the .then() block. That means function B is also async. (In the simple example below you can omit the async keyword on function A.) You need to declare function B as async and then await the completion of function A.
function A() {
return jQuery.get("example.com").done(function(result) {
if (result.indexOf("Example")) {
console.log("sucess", result);
} else {
console.log("Fail", result);
}
});
}
async function B() {
await A().then(function(result) {
console.log("Res:");
// moved to a separate console log, otherwise dev tools might print
// a lot of [objectObject] instead of the actual result
console.log(result);
})
}
B();
If you want to do other stuff inside of function A and then eventually return the result, you can play around with something more like
async function A() {
const response = await jQuery.get('example.com');
// more stuff…
return response;
}
I fixed it by moving return statement outside from the .done(function(){}) and by adding await before jQuery chain. And instead of returning value inside that callback function, now I only pass there value to variable, which is later returned outside of that callback function.
async function A(){
let res = 0;
await jQuery.get("example.com").done(function(result){ //await was added
if (result.indexOf("Example")){
console.log("sucess");
res = 1; // value is passed to variable, which is returned as result outside this callback function
} else {
console.log("Fail");
res = -1;
}
})
return res; // return statement is outside the callback function
}
function B(){
A().then(function(result){
console.log("Res:" + result);
})
}
B();
I guess the problem was, as #cjl750's answer says, that return statement inside the callback function isn't "seen" as a "true return statement" of that function. So function B() probably saw function A() as a function, which doesn't return anything.
EDIT
I've rewritten the code using $.Deferred() object. It's probably better now. Await is now moved to function B(), it doesn't wait for jQuery chain anymore.
function A(){
var dfd = $.Deferred();
jQuery.get("google.com").then(function(result){
if (result.indexOf("Example")){
console.log("sucess");
dfd.resolve(1);
} else {
console.log("Fail");
dfd.resolve(-1);
}
})
return dfd.promise();
}
async function B(){
await A().then(function(result){
console.log("Res:" + result);
})
}
B();
I am new to Javascript and am facing trouble dealing with Async/Await. Here is my code, as per my understanding adding await puts on hold the function
Here, inside foo, it should put on hold the code at checker() and move to running the commands outside foo, but instead it executes the checker() function before console.log('the end').
function checker() {
console.log('inside checker');
return "Ok"
}
async function foo() {
let a = await checker(); // Shouldn't using await here let next line outside foo to execute
console.log("mid", a);
}
console.log(1);
foo();
console.log('the end');
// Output coming is:
//1
//inside checker
//the end
//mid Ok
Can someone please tell me what properties are making it to behave this way. I know there's something that I am missing but can't figure out what.
Your checker function is not asynchronous, but you also need to do something that is actually async within it.
At the moment, all of the promises are instantly resolved which provides no opportunity for later code to run.
We need to actually create a promise, merely defining a function as async isn't enough unless something inside is returning a promise, so we return a new promise which is resolved by the setTimeout callback.
Note that the timeout period is 0 which is enough to cause the javascript event loop to be invoked, which allows the next statement(s) after calling foo to be processed. Changing this to any positive integer will change the execution time but not the order of events.
function checker() {
return new Promise(resolve => {
setTimeout(() => resolve('Ok'), 0)
})
}
function foo() {
let a = checker();
console.log(new Date(), "mid");
return a
}
(async () => {
console.log(new Date(), 'start');
foo().then(v => console.log(new Date(), 'eventually', v));
console.log(new Date(), 'the end');
})()
You didn't define your function as async
function checker() {
console.log('inside checker');
return "Ok"
}
It should be
async function checker() {
console.log('inside checker');
return "Ok"
}
await tells your code to wait for the function to finish. If you want to continue running without waiting, then you shouldn't use the await keyword. async also needs to be on the function that you want to run asynchronously, in this case checker()
async function checker() {
console.log('inside checker');
return "Ok"
}
function foo() {
let a = checker();
console.log("mid", a);
}
console.log(1);
foo();
console.log('the end');
foo is an async function, ie the code inside it will wait if you use the await keyword
But the foo function returns a promise. so if you want to wait for foo either use
await foo();
or use
foo().then(() => { console.log('the end'); })
I create microservice and in one function I have three other functions, for example:
functionA();
functionB();
functionC();
return json({status: processed});
All functions are synchronous, but they execute Math operations. functionB is the longest performed, so I would like to use it as for example HTTP request, which is asynchronous.
I tried:
functionB() {
return new Promise(//etc...);
}
and
async functionB() {
return 1;
}
but my function still is synchronous.
How does Node recognize which function can be run immediately or should go to event loop? Why Promise and async not working in this case?
This logs 'foo' then 'bar'
function foobar() {
var p = Promise.resolve();
p.then(() => console.log('bar'));
console.log('foo');
return p;
}
While this logs 'bar' then 'foo'.
function foobar() {
var p = new Promise((resolve, reject) => {
console.log('bar');
resolve();
})
console.log('foo');
return p;
}
This is because the callback (resolve, reject) => ... passed to new Promise is called immediately as part of the promise creation process, thus the callback is actually a sync function.
Similarly with async function.
async function B() {
return 1;
}
Marking a sync function async doesn't magically make it "async". If the function body (return 1 in this example) consists of all synch operations, then it is the same as the callback passed to new Promise, it's still executed synchronously when called.
If you really need to defer the task to next loop iteration, use setTimeout(cb) or setImmediate(cb) is more promising. That cb is async for sure.
This is a simple version of what I'm trying to do in my application. I have an if statement which evaluates the result of a function call and then populates an array if the statement comes back as true. AFTER the if statement is completely finished, I want to run some more code such as the console.log as seen below.
I understand that the if's evaluation is taking too long to finish and javascript just continues to the console.log because of its asynchronicity. How do I make the code wait for the if statement to complete?
var tabs = [];
if (isTrue()) {
tabs.push('some string');
}
console.log(tabs[1]);
function isTrue() {
setTimeout(function() {
return true;
}, 500)
}
You can just wrap your code in a Promise and consume the returned values by calling then on it:
var tabs = [];
isTrue().then(res => {
if (res) {
tabs.push('some string');
}
return tabs;
}).then(arr => {
console.log(arr);
});
function isTrue() {
//Just wrap your existing code in a Promise constructor
return new Promise((resolve, reject) => {
setTimeout(() => {
//Pass whatever value you want to consume later to resolve
resolve(true);
}, 500)
});
}
You could pass a callback to the isTrue() function, something like:
function isTrue(_callback) {
setTimeout(function() {
// code here
// Call the callback when done
if (typeof(_callback) === 'function')
_callback(tabs);
});
}
function showTabs(tabs) {
console.log(tabs[1]);
}
isTrue(showTabs);
Ought to work.
Using modern javascript, you can achieve that using promises and async/await:
const isTrue = () => new Promise(resolve => setTimeout(resolve, 500, true));
// you can only use `await` inside an `async` function
async function main() {
// better use `let` instead of `var` since `let` is block scoped,
// see:
// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let>
let tabs = [];
if (await isTrue()) {
tabs.push('some string');
}
// array's index start by 0, not 1
console.log(tabs[0]);
}
main();
(this code also use arrow functions for isTrue.)
isTrue() returns undefined. The return true inside of the setTimeout callback will return back to the timeout call, not to the isTrue() call. The code executes immeadiately and there is no asynchronity involved (except for that timer that does nothing).
1.I'm trying to chain some promises with using functions on a global promise object. The chain sequence doesn't work as I thought. The following code output 1 3 4 2.
2.I wonder what is the reason for this. My thought is in the variable declaration pass, p.then() function registered but not its following promises, not until the p.then() function returns, it start to push the second then function in callback queue.
To answer the question why I'm doing this, I was trying to use an builder pattern for a sequence of actions.
For example, builder().setupTestEnv().connectToDatabase().setupAuthServer().setupAuthClient(). Each function in this chain is intended to do _globalPromiseObject.then() to chain up following actions.
I know an alternative solution for this is, end the builder chain with an execute() call, which run Q.all() to run all promises in sequence. But just curious about this behavior of promise chain.
const Q = require('q');
const p = Q();
p
.then(
function(){
console.log(1);
}
)
.then(
function(){
console.log(2);
}
);
function foo(){
p.then(
function () {
console.log(3);
}
);
}
function bar(){
p.then(
function () {
console.log(4);
}
);
}
foo();
bar();
Not sure if this 100% answers your question, but perhaps it is helpful to look at this in terms of meaningful statements in your example:
p.then()
foo()
bar()
finally, #1's then fires
Those three operations happen immediately after each other, synchronously. Let's remove the foo and bar wrappers, as if you wrote their contents in place of calling them:
p.then(/* log 1 */)
p.then(/* log 3 */) contents of foo
p.then(/* log 4 */) contents of bar
finally, #1's then fires
You can return foo() and bar() from the respective function, then pass foo and bar to .then() .then(foo).then(bar) or return foo() and bar() from .then(function(){ return foo() })
const p = Promise.resolve();
p
.then(
function() {
console.log(1);
}
)
.then(
function() {
console.log(2);
}
)
.then(function() {
return foo()
})
.then(function() {
return bar()
})
function foo() {
return p.then(
function() {
console.log(3);
return
}
);
}
function bar() {
return p.then(
function() {
console.log(4);
return
}
);
}