So I've been trying to google my answer but had no luck finding it. I'm wondering how I can await a value to be defined by the use of promises, not a brute-force method like using:
while(true){ Check for condition and then break }
This was my initial brute-force approach but It obviously isn't a good solution:
const awaitToken = new Promise((resolve, reject) => {
while(true){
if(getState().auth.token){
resolve(true)
break;
}
}
})
**
EDIT: The getState method isn't asynchronous otherwise it would be way easier and why I'm implementing this is because there is a small delay from when the user is signed in to when the token is available in redux state
**
I'm working on a react-redux project where I want to implement this however, my code is irrelevant because I don't want a case-specific answer. I would appreciate any help!
Here is a non-blocking solution for using synced functions an easy way in promises.
An additional timeout can save you a lot of waiting time.
let arrivedToken = new Promise((resolve, reject) => {
/* how often you wanna check? */
let interval = 20;
/*how long do you want to wait? */
let timeOut = 4000;
let timer = setInterval(() => {
timeOut -= interval;
if (timeOut < 1) {
clearInterval(timer);
reject(new Error('catching token timed out'));
}
let token = getState().auth.token;
if (token)
resolve(token);
}, interval);
};
so you can handle the success or even the failure:
arrivedToken
.then(token => {
/* whatever you want */
})
.catch(error => {
/* handle the timeout */
})
;
Redux allows you to subscribe to a store. The callback will be called whenever an action is dispatched.
Meaning you could do something like this:
const awaitToken = new Promise(resolve => {
if (getState().auth.token) return resolve(true);
const unsubscribe = subscribe(() => {
if (!getState().auth.token) return;
unsubscribe();
resolve(true);
});
});
Additional info about subscribe can be found here. You might also want to add a timeout, but that might depend on the use case.
Push vs. Pull
I'm going to make some assumptions given the way you asked your question: The assumption is no-one has explained the Push v Pull dichotomy. It's extremely important to understand to solve these types of problems in the future without SO's community.
Promises and callbacks were designed by the ECMA body to enable developers to PULL for results of asynchronous tasks. You can think of PULL-ing as picking up the telephone and calling your friend asking him if your package has been delivered at his address that you used on your delivery form. Obviously you're not going to stay on the call until the package arrives so you continuously have to iterate this process until your friend says, "yes, you're package has arrived" (e.g. Promise.resolve(package) || cb('package has arrived')).
Then the ECMA body delivered us ES8. And with it, a PUSH methodology which solves exactly the problem that you're beating your head against quite admirably I might add. The async/await dichotomy enables a developer to no longer have to pick up the phone and call their friend. Instead, your friend picks up the phone and calls you and says "Hey man, come get your stuff off my porch, it's arrived." This is a PUSH. async/await & generators
More Verbosity on async/await theory if you desire here
Solutions
generators
function * fetchToken() {
const { auth } = getToken(); // getToken() is asynchronous and BLOCKs control flow until value is returned.
yield auth.token;
}
const tokenGen = fetchToken();
const { value: token } = tokenGen().next();
console.log('token: ', token); // [jwt token]
async/await
async function fetchToken() {
const { auth } = await getToken(); // await BLOCK's control flow until the function resolves.
return auth.token;
}
const token = fetchToken();
console.log('token: ', token); // [jwt token]
Related
I know one must not block the loop, I know use call backs, and I know ES6 await. The more I research this the more it reaffirms it.
But sometimes your hands are tied. Is there a way to tell JavaScript, please go check on your event queue, and service those, then come back here before continuing execution.
Something like inspired by the MDN docs:
if (queue.hasNextMessage()) {
queue.processNextMessage()
}
There are similar threads about use datetime to wait a duration, but I don't know how the long other event thread will take, been looking at polling the promise status, but it appears to be a dead end.
The context is I have to override a validation callback. The caller of the callback does not wait for a promise to resolve (That I cant change).
Here is the test setup showing the concept. I have made a few attempts, but none of them work because they are always stuck in the main loop.
// The validate function depends on a fetch call which takes time.
// Free to change this.
function validate() {
return fetch(url).then(response => response.json())
.then(data => {console.log(data); return true;})
.catch(msg => {console.log(msg); return false;})
}
// Cannot change this function, I am not in control of it
function CallValidate() {
console.log("Validation Result: ", Boolean(validate()));
}
// This is the setup for when test passes
let url = 'http://api.open-notify.org/astros.json';
CallValidate();
// This is the setup for when test fails
// This currently fails because the promise objects is being evaluated
// to true, instead of waiting for its response.
url = 'http://DUMMY.NOT.WORKING.URL';
CallValidate();
Is there a way to tell JavaScript, please go check on your event queue, and service those, then come back here before continuing execution.
No, but you can do something very similar: divide your computation into several tasks. In Node.js, you can use setImmediate() to queue a task. In the browser, you can use messages, as outlined by this answer.
Example:
function setImmediate(callback) {
const channel = new MessageChannel();
channel.port1.onmessage = () => {
callback();
};
channel.port2.postMessage("");
}
console.log("Task 1");
setImmediate( () => {
console.log("Task 2");
});
Boolean(validate()) will always evaluate to true, because validate returns a Promise which is a truthy value no matter what it resolves to.
If you can't change CallValidate, you might still be able to lift up the fetch call. But I'm not sure if that's an option for you.
async function validateUrl(url) {
const valid = await fetch(url).then(response => response.json())
.then(data => {console.log(data); return true;})
.catch(msg => {console.log(msg); return false;});
function validate() {
return valid;
}
function CallValidate() {
console.log("Validation Result: ", Boolean(validate()));
}
CallValidate();
}
// assuming you are in async function context
await validateUrl('http://api.open-notify.org/astros.json');
await validateUrl('http://DUMMY.NOT.WORKING.URL');
If moving the function is also no option I would ditch the CallValidate code and either write something yourself, or pick another library/helper/etc that does handle asynchronous functions (with promise return values).
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 2 years ago.
I am getting into Node, and being thrown into the world of async programming.
I thoroughly read this article on Mozilla's site (along with many other links teaching about the async and await keywords):
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await
I have a project I am starting that will require numerous database calls, one after another. Some queries will rely upon the previous one's results. That being said, I decided I better practice and write some testing code.
Here is my testing code:
var users, items;
const getData = async function(){
// This is a DB call. Will take
// a little bit of time to complete.
setTimeout(() => {
var queryResults = "A list of items";
items = queryResults;
}, 1000);
return items;
}
const getUsers = async function(){
setTimeout(() => {
var queryResults = "A list of items";
users = queryResults;
}, 1000);
return users;
}
const init = async function(){
var itemSuccess = await getData();
var userSuccess = await getUsers();
console.log(`Here is your items: ${items}, and here are your users: ${users}`);
}
init();
My code failed with:
Here is your items: undefined, and here are your users: undefined
So naturally I headed back to Mozilla. I re-read the docs, and tried a few changes. Still, no success. Ultimately I ended up back at my original code above.
I cannot see why this is failing. I am simulating the time a query would take by using a timeout. If async does what it says, both functions should return their value, and then my console log should print out the correct results.
Does anyone see where I am going wrong?
Thank you.
Show us your REAL code with the actual database calls in it and we can help you much more specifically, including showing you working code. Please resist the temptation to post questions with pseudo-code. Show real code and we can help you so much faster and better if you show us the real code.
await ONLY does something useful when you await a promise that resolves or rejects when something you are interested in completes or errors.
It has no magic to somehow know when a a setTimeout() or any other asynchronous operation is done doing whatever it does.
So, when you do this:
var itemSuccess = await getData();
And, getData() looks like this:
const getData = async function(){
// This is a DB call. Will take
// a little bit of time to complete.
setTimeout(() => {
var queryResults = "A list of items";
items = queryResults;
}, 1000);
return items;
}
All you end up doing is:
var itemSuccess = await undefined
because your getData() function doesn't return a promise and, in fact, it doesn't even return the items because it returns BEFORE your timer so items (which doesn't appear to be declared properly here) has not yet received its value.
So, I would suggest you start back with the basics and go read what await really does. Make sure you understand how it interacts with a promise since it's only useful when used with a promise. And, then learn how to make your asynchronous operations return promises that are connected to when your asynchronous operations complete. Then, and only then, can you make proper use of await.
In a well organized world, you make sure that all your asynchronous operations are already returned promises and then you can async/await and .then() and .catch() to control the flow of all your asynchronous operations. In many cases, this involves learning the promise interface for whatever you're using. For example, modern versions of node.js have an entire promise interface for the file system in fs.promises.
In a few cases, there may not exist a promise interface for some library you're using and you may have to wrap the asynchronous operation in a promise to make your own promise interface. util.promisify() is built-into node.js to help you do that.
If you show the ACTUAL code, include which database you're using and the actual database call you're trying to make, then someone here can probably help you with the proper way to use the promise interface on the database. This pseudo code prevents us from helping you that specifically. Without your actual code and knowing the actual DB calls you're making in a specific DB, it's hard for us to advise much more than go use the promise interface to your database and learn how to use those promises properly. Happy to help more specifically, but we need to see you REAL code to do that.
And, lastly in Javascript if you're assigning a value to something in a higher scope from within any asynchronous callback, there's a 99.99% chance you're doing things wrong. The only place you can actually use that value is inside the callback itself or in a function that you call from there and pass the value to. So, when you do items = queryResults, where items is declared in a couple scopes above you, then alarm bells should go off that this is not going to work for you. It's not how you program with asynchronous code in Javascript, not just for style reasons, but because it doesn't work.
Use:
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
instead of
setTimeout(() => {
}, 1000);
await waits for a Promise to resolve.
// normal function that returns a promise
const getData = function(){
// This is a DB call. Will take
// a little bit of time to complete.
return new Promise(resolve => {
setTimeout(() => {
var queryResults = "A list of data";
resolve(queryResults);
}, 1000);
});
}
const getUsers = function(){
return new Promise(resolve => {
setTimeout(() => {
var queryResults = "A list of users";
resolve(queryResults);
}, 1000);
});
}
const init = async function(){
var itemSuccess = await getData();
var userSuccess = await getUsers();
console.log(`Here is your items: ${itemSuccess}, and here are your users: ${userSuccess}`);
}
init();
An async function does 2 things.
it makes it possible to use the await keyword to wait for promises.
it makes the function automatically return a promise itself that wraps whatever the function returns
async function foo() {
return 123;
}
const v = foo();
console.log(v instanceof Promise);
v.then(value => console.log(value));
A more normal database query might look something like this
async function dbQuery(queryUrl) {
const res = await fetch(queryUrl); // fetch returns a promise that resolves to a Response
return res.json(); // res.json returns a promise that resolves to the body of response parsed as json.
}
async function main() {
const films = await dbQuery('https://greggman.github.io/doodles/test/data/films.json');
console.log(JSON.stringify(result, null, 2));
}
main();
I understand that this is a basic question, but I can't figure it out myself, how to export my variable "X" (which is actually a JSON object) out of "for" cycle. I have tried a various ways, but in my case function return not the JSON.object itself, but a "promise.pending".
I guess that someone more expirienced with this will help me out. My code:
for (let i = 0; i < server.length; i++) {
const fetch = require("node-fetch");
const url = ''+(server[i].name)+'';
const getData = async url => {
try {
const response = await fetch(url);
return await response.json();
} catch (error) {
console.log(error);
}
};
getData(url).then(function(result) { //promise.pending w/o .then
let x = result; //here is real JSON that I want to export
});
}
console.log(x); // -element is not exported :(
Here's some cleaner ES6 code you may wish to try:
const fetch = require("node-fetch");
Promise.all(
server.map((srv) => {
const url = String(srv.name);
return fetch(url)
.then((response) => response.json())
.catch((err) => console.log(err));
})
)
.then((results) => {
console.log(results);
})
.catch((err) => {
console.log('total failure!');
console.log(err);
});
How does it work?
Using Array.map, it transforms the list of servers into a list of promises which are executed in parallel. Each promise does two things:
fetch the URL
extract JSON response
If either step fails, that one promise rejects, which will then cause the whole series to reject immediately.
Why do I think this is better than the accepted answer? In a word, it's cleaner. It doesn't mix explicit promises with async/await, which can make asynchronous logic muddier than necessary. It doesn't import the fetch library on every loop iteration. It converts the server URL to a string explicitly, rather than relying on implicit coercion. It doesn't create unnecessary variables, and it avoids the needless for loop.
Whether you accept it or not, I offer it up as another view on the same problem, solved in what I think is a maximally elegant and clear way.
Why is this so hard? Why is async work so counterintuitive?
Doing async work requires being comfortable with something known as "continuation passing style." An asynchronous task is, by definition, non-blocking -- program execution does not wait for the task to complete before moving to the next statement. But we often do async work because subsequent statements require data that is not yet available. Thus, we have the callback function, then the Promise, and now async/await. The first two solve the problem with a mechanism that allows you to provide "packages" of work to do once an asynchronous task is complete -- "continuations," where execution will resume once some condition obtains. There is absolutely no difference between a boring node-style callback function and the .then of a Promise: both accept functions, and both will execute those functions at specific times and with specific data. The key job of the callback function is to act as a receptacle for data about the asynchronous task.
This pattern complicates not only basic variable scoping, which was your main concern, but also the issue of how best to express complicated workflows, which are often a mix of blocking and non-blocking statements. If doing async work requires providing lots of "continuations" in the form of functions, then we know that doing this work will be a constant battle against the proliferation of a million little functions, a million things needing names that must be unique and clear. This is a problem that cannot be solved with a library. It requires adapting one's style to the changed terrain.
The less your feet touch the ground, the better. :)
Javascript builds on the concept of promises. When you ask getData to to do its work, what is says is that, "OK, this is going to take some time, but I promise that I'll let you know after the work is done. So please have faith on my promise, I'll let you know once the work is complete", and it immediately gives you a promise to you.
That's what you see as promise.pending. It's pending because it is not completed yet. Now you should register a certain task (or function) with that promise for getData to call when he completes the work.
function doSomething(){
var promiseArray = [];
for (let i = 0; i < server.length; i++) {
const fetch = require("node-fetch");
const url = ''+(server[i].name)+'';
const getData = async url => {
try {
const response = await fetch(url);
return await response.json();
} catch (error) {
console.log(error);
}
};
promiseArray.push(getData(url)); // keeping track of all promises
}
return Promise.all(promiseArray); //see, I'm not registering anything to promise, I'm passing it to the consumer
}
function successCallback(result) {
console.log("It succeeded with " + result);
}
function failureCallback(error) {
console.log("It failed with " + error);
}
let promise = doSomething(); // do something is the function that does all the logic in that for loop and getData
promise.then(successCallback, failureCallback);
I was wondering if someone could help me with this issue that I have...
Our client has an Legacy API which retrieves messages from users, and they want us to implement a polling mechanism for it that, based on an specific interval, updates the information within the page. Period.
They want to have a reliable polling strategy so (as you may already know) I'm using setTimeout to pull that off.
TL;DR: Does anyone one of you knows how to pull out an efficient polling utility that doesn't leak memory?
I'm trying to pull off an utility that allows me to add certain actions to a "polling list" and run the "polling" right there.
For example, I have an "actions list" similar to this:
const actions = new Map();
actions.set('1', ('1', {
action: () => {
console.log('action being executed...');
return 'a value';
},
onFinished: (...param) => { console.log(param); },
name: 'name of the action',
id: '1'
}));
I'm using Map for both api convenience and lookup performance and I'm adding a fake action to it (some of the params might not be needed but they're there for testing purposes).
Regarding the polling, I've created a delay fn to handle the timeout as a Promise (just for readability sake. It shouldn't affect the call stack usage whatsoever):
function delay(timeout) {
return new Promise(function delay(resolve) {
setTimeout(resolve, timeout);
});
}
And the polling fn that I came up with looks like this:
async function do_stuff(id, interval) {
const action = actions.get(id);
// breakout condition
if (action.status === 'stop') {
return;
}
console.log('processing...');
const response = await action.action();
console.log('executing action onFinished...');
action.onFinished(action.name, response);
delay(interval).then(function callAgain() {
do_stuff(id, interval);
});
}
I've used async/await in here because my action.action() will be mostly async operations and I'm using .then after the delay because I want to use the browser's EventTable to handle my resolve functions instead of the browser's stack. Also, I'm using named functions for debugging purposes.
To run the polling function, I just do:
const actionId = '1';
const interval = 1000;
do_stuff(actionId, interval);
And to stop the poll of that particular action, I run:
actions.get(actionId).status = 'stop'; // not fancy but effective
So far so good.... not! This surely has a ton of issues, but the one that bothers me the most of the JS Heap usage.
I ran a couple of tests using the Performance Tab from Chrome DevTools (Chrome version 64) and this is what I got:
Using an interval of 10 milliseconds
- 1000ms: polling started
- 10000ms: polling stopped
- 13000ms: ran a manual GC
Using an interval of 1 second
1000ms: polling started
10000ms: polling stopped
13000ms: ran a manual GC
Does anyone know why is this behaving like this? Why the GC it's running more frequently when I decrease the interval? Is it a memory leak or a stack issue? Are there any tools I could use to keep investigating about this issue?
Thanks in advance!
Stuff that I've read:
http://reallifejs.com/brainchunks/repeated-events-timeout-or-interval/ (why choosing setTimeout instead of setInterval)
Building a promise chain recursively in javascript - memory considerations
How do I stop memory leaks with recursive javascript promises?
How to break out of AJAX polling done using setTimeout
https://alexn.org/blog/2017/10/11/javascript-promise-leaks-memory.html
PS: I've putted the snippet right here in case anyone wants to give it a try.
const actions = new Map();
actions.set('1', ('1', {
action: () => {
console.log('action being executed...');
return 'a value';
},
onFinished: (...param) => { console.log(param); },
name: 'name of the action',
id: '1'
}));
function delay(timeout) {
return new Promise(function delay(resolve) {
setTimeout(resolve, timeout);
});
}
async function do_stuff(id, interval) {
const action = actions.get(id);
// breakout condition
if (action.status === 'stop') {
return;
}
console.log('processing...');
const response = await action.action();
console.log('executing action onFinished...');
action.onFinished(action.name, response);
delay(interval).then(function callAgain() {
do_stuff(id, interval);
});
}
/*
// one way to run it:
do_stuff('1', 1000);
// to stop it
actions.get('1').status = 'stop';
*/
I want to make a function that get the reslt of fingerprint2.js
Fingerprint2 is a Modern & flexible browser fingerprinting library http://valve.github.io/fingerprintjs2/
Usage:
new Fingerprint2().get(function(result, components){
console.log(result); //a hash, representing your device fingerprint
console.log(components); // an array of FP components
});
whatever try i did to get result of Fingerprint2 outside of new Fingerprint2().get(function(result, components){ was failed.
like Global vars and cookie because Fingerprint2().get(...) is asynchronous
Can it be written like a function to get fingerprint2 result?
for example:
var secure = getmefingerprint2();
Leverage with ES2017 feature async/await, you can use Fingerprint2.getPromise() like this:
(async () => {
const components = await Fingerprint2.getPromise();
const values = components.map(component => component.value);
const murmur = Fingerprint2.x64hash128(values.join(""), 31);
console.log('fingerprint:', murmur);
)()
See get and getPromise in Fingerprint2 Doc
This should be a comment but its a bit long.
Even if it were possible, you would be bypassing the published api, meaning you would have to maintain a fork of the original code. You would also need to invoke the functionality synchronously - and fingerprintjs2 runs asynchronously for good and obvious reasons.
You seem to be asking about an XY problem
How you should sole it depends on what you intend to do with the fingerprint after it has been captured.
You can't make async code act completely synchronous. However, you can use async/await, if your target browser has support, but it's not universally supported. Also, it only looks synchronous inside the async function
The basic idea is to return a promise, then await it inside an async function:
const getmefingerprint2 = async () => {
const secure = await (new Promise(resolve => {
new Fingerprint2().get((result, components) => resolve(result) )
}))
// do things with secure, whatever you return is thenable
return secure
}
that function could be called like this (because of Promises):
getmefingerprint2().then(result => {
// do stuff with result
})
but also, inside the async function, you could treat secure like you got it synchronously.
If you really wanted to make your async code act more sync (might be useful for other async code, too, if you hate async), you could wrap all your code in an async function, then use await to get async stuff:
const getFingerprint = () => new Promise(resolve => {
new Fingerprint2().get((result, components) => resolve(result) )
})
const main = async () => {
// do some of your app here
const secure = await getFingerprint()
// do more stuff here
}
main()
Or as an IIFE:
(async() => {
// do some of your app here
const secure = await getFingerprint()
// do more stuff here
})()
These are just kinda hacky workarounds that allow you to escape the burden of async code, which is maybe worth just getting to know, as it will make a better app. If you restructure your code to only have the things that depend on secure inside the callback, you'll get better performance, unblocked UI, and a more dynamic flow that is easy enough to reason about, once you get used to it.