In a React Native project, I wrote this function using Promise to do a job asynchronously;
function doEncryptionAsync(params) {
return new Promise(
function (resolve, reject) {
// Async code started
console.log('Promise started (Async code started)');
// The job that takes some times to process
var encrypted_value = new EncryptedValue(params);
if (true) {
resolveencrypted_value
}
else {
reject("Error while encrypting!");
}
}
)
}
And I call that in my Redux action;
export const encrypt = ( params ) => {
return (dispatch) => {
dispatch({
type: type.ENCRYPT
});
// Sync code started
console.log('Started (Sync code started)');
doEncryptionAsync(params)
.then((response) => {
// Async code terminated
console.log('Promise fulfilled (Async code terminated)');
encryptSuccess(dispatch, response);
})
.catch((error) => {
console.log(error);
encryptFail(dispatch);
});
// Sync code terminated
console.log('Promise made (Sync code terminated)');
}
}
It works, but not asynchronously! My main thread seems to be blocked until doEncryptionAsync() returns. The line console.log('Promise made (Sync code terminated)') runs, but not immediately!
My output for logs is like this;
// OUTPUT Simulation
Started (Sync code started) at time x
Promise started (Async code started) at time x
Promise made (Sync code terminated) at time (x + 2sec)
Promise fulfilled (Async code terminated) at time (x + 2sec)
My question is what's wrong with my approach to implement a AsyncTask?!
JavaScript's asynchronous behavior is only relevant for IO blocking functions. Meaning, that instead of waiting for an IO function, the event loop keeps running.
Seeing as JS is single threaded, CPU bounded computations take up the thread, and cannot be done asynchronously.
Your only recourse, then, is to create a native module that will do the calculation in a different thread for you, and then call a JS callback when it's done.
Related
I have written a handler function inside my nextjs page/api folder;
handler(req, res) {}
Am using #influxdata/influxDb-client as mentioned in the documentation. Am using
from(queryAPI.rows(query).pipe(....).subscribe(next(value)=> {results.push(value}, complete(console.log(results); res.status(200).json(results)}
Am getting all the query value, once the observable is completed. it works most of the time.
Am pushing the intermediate results in the next part of the subscriber and trying to send the results back to client in the complete part of the subscriber. I want the request handler to wait till i get all my values from influx DB query in the complete part of the subscriber and can send the value back to client..
But the issue "Handler function will not Wait till the observable is completed". Handler function returns, before the observer gets completed. Am getting error: API resolved without sending a response...
I get all the values only when the observer is completed.
I don't know how to handle the scenario.
How can I make the handler function wait until the observable is completed?
I found the solution for the same
I used new Promise() with await, added my observable inside this promise and resolved the promise on Complete of the subscribe.
Code will look like the following :
export async function handler (req, res) {
const results=[];
await new Promise((resolve, reject) => {
from((queryAPIs.rows(query))
.pipe(map(({values, tableMeta}) => tableMeta.toObject(values)))
.subscribe(
{
next(object) => {results.push(object)}
complete() => { resolve (results) }
error(err) => { reject (err) }
});
res.status(200).send(results);
}
}
My published Cloudflare Worker (wrangler publish --env environment_name) is timing out for clients, but not when
running locally (e.g. by using cfworker, a nice tool to emulate cloudflare workers locally)
or running in preview (wrangler preview --env environment_name).
A summary of my worker:
addEventListener('fetch', async (event) => {
const fetchEvent = event as FetchEvent
const results = await doSomeWork() // returns a promise
return fetchEvent.respondWith(new Response(JSON.stringify(results)))
})
My wrangler tail (production logs) output does complete (after I placed console.log statements in doSomeWork. There were no errors, and I got {"outcome":"ok"... in wrangler tail. I would have expected to get error code 1102 (Worker exceeded CPU time limit.) if time-out was happening.
It turns out that addEventListener cannot be passed an async function (or one that returns a promise). The fetchEvent.respondWith does accept a promise however. This is not written in the documentation, but I discovered this in lib.webworker.d.ts.
To do asynchronous work, you must return a promise to fetchEvent.respondWith instead:
So your alternatives are to:
Pass a promise to respondWith
addEventListener('fetch' (event) => {
const fetchEvent = event as FetchEvent
const responsePromise = doSomeWork().then((results) => new Response(JSON.stringify(results))
return fetchEvent.respondWith(responsePromise))
})
Or pass the result of an async function to respondWith (still a promise, I told you, you must return a promise)
addEventListener('fetch' (event) => {
const fetchEvent = event as FetchEvent
const responsePromise =
return fetchEvent.respondWith(async () => {
// I would put this async function in a different file (handlers.ts/.js), and name it `doSomeWorkHandler` to make it more readable though
const results = await doSomeWork()
return new Response(JSON.stringify({hello: "world"}))
}))
})
Why no timeout error?
The reason the timeout error doesn't happen is because even though Cloudflare Workers limits your CPU execution time to 10ms on the free plan, it doesn't stop your worker because you're not using the CPU in this bug/ edge case. It's doing nothing.
I am not sure about this question if this can be implemented or not.
I am using node.js with express.js and MySQL database.
I have a few records in MySQL database. These records are updating continues.
So, suppose I fetch some records from MySQL and start operations on each record with Promise.all using demoFunction function which is returned promise.
In this function, I am trying to check for new records in MySQL database. If I got new records then I want to push this new record's operation into current Promise.all queue. Is this possible? If not possible then how can I achieve this goal with continues execution?
So, my code is like,
const demoFunction = (arg1, arg2) => {
checkForNewData();
return new Promise((resolve, reject) => {
// Rest of my code is here for this function
// This function will be take around 5 to 10 mins
});
};
const dataFromDatabase = "Here i'm getting some data into array of object from SQL database";
let allPromises = dataFromDatabase.map((obj) => demoFunction(obj.arg1, obj.arg1));
const checkForNewData = () => {
const newDataFromDatabase = "Here i'm getting some new data into array of object from SQL database";
for (let i = 0; i < newDataFromDatabase.length; i++) {
allPromises.push(demoFunction(newDataFromDatabase[i].arg1, newDataFromDatabase[i].arg2));
}
};
return Promise.all(allPromises)
.then(() => {
// response
})
.catch((e) => {
console.log(e);
})
In this function, I am trying to check for new records in MySQL database. If I got new records then I want to push this new record's operation into current Promise.all queue. Is this possible?
Nope, Promise.all takes a finite and set number of promises and waits for all of them to complete.
If not possible then how can I achieve this goal with continues execution?
Well, a promise is just a value - if you have a promise for something then execution has already started somewhere else. You can always execute a second .all but what happens if records were added in the meantime?
It's fine to do:
Promise.all(allPromises).then(() => Promise.all(allPromises)).then(() => {
});
But at that point you're better off just waiting for the checkNewData call to finish before calling the Promise.all since otherwise you're introducing a race between checkAllData and the Promise.all
A promise is a "one time" thing, consider using an async iterator if you want to process results (note, this requires Node 12):
async function* getRecordData() {
for await(const item in getPromisesOfInitDataFromDatabase()) {
yield item; // or process it
}
while(true) { // or how often you want
for await(const item of getNewDastaFromDatabase()) {
yield item; // or process it
}
await sleep(3000); // or some sleep timeout to not constantly poll
}
}
Then elsewhere:
(async () => {
for await(const item of getRecordData()) {
// items are available here one by one, including new items in the database
}
})();
I'm having a hard time wrapping my brain around this pattern I am trying to implement so I'm hoping the stack overflow community might be able to help me work through a solution to this.
Currently I use redux-thunk along with superagent to handle calls to me API and syncing it all up with redux
An example of this might look like
export const getUser = (id) => {
return (dispatch) => {
const deferred = new Promise((resolve, reject) => {
const call = () => {
API.get(`/users/${id}`)
.then((response) => response.body)
.then((response) => {
if (response.message === 'User found') {
serializeUser(response.data).then((response) => {
resolve(response);
});
} else {
reject('not found');
}
}).catch((err) => {
handleCatch(err, dispatch).then(call).catch(reject)
});
}
call()
});
return deferred;
};
};
In the case where the server comes back with a 200 and some data I continue on with putting the data into the store and rendering to the page or whatever my application does.
In the case I receive an error I have attempted to write a function that will intercept those and determine if it should show an error on page or in the case of a 401 from our API, attempt a token refresh and then try to recall the method...
import { refreshToken } from '../actions/authentication';
export default (err, dispatch) => {
const deferred = new Promise((resolve, reject) => {
if (err.status === 401) {
dispatch(refreshToken()).then(resolve).catch(reject)
} else {
reject(err);
}
})
return deferred;
};
This works, however, I have to add this to each call, and it doesn't account for concurrent calls that should not attempt to call if there is a refresh in progress.
I've seen some things in my research on this topic that maybe redux-saga could work but I haven't been able to wrap my brain around how I might make this work
Basically, I need something like a queue that all my API requests will go into that is maybe debounced so any concurrent requests will just be pushed to the end and once a timeout ends the calls get stacked up, when the first call gets a 401 it pauses the queue until the token refresh either comes back successful, in which case it continues the queue, or with a failure, in which case it cancels all future requests from the queue and sends the user back to a login page
The thing I would be worried about here is if the first call in the stack takes a long time, I don't want the other calls to then have to wait a long time because it will increase the perceived loading time to the user
Is there a better way to handle keeping tokens refreshed?
I am using mocha and selenium-webdriver for E2E tests. Most of the tests are async and I am using async/await functions to handle this. Unfortunately right now I can't get a single one done. Here is what my code looks like:
describe('Some test', function () {
before(function () {
driver.navigate().to('http://localhost:3000')
})
after(function () {
driver.quit()
})
it('should display element', async function () {
let elementFound = false
try {
await driver.wait(until.elementIsVisible(driver.findElement(By.className('element'))), 1000)
assessForm = await driver.findElement(By.className('element')).isDisplayed()
assert.ok(elementFound)
console.log('elementFound', elementFound)
} catch (err) {
console.log(err)
assert.fail(err)
}
})
})
The problem that is happening seems to be that the after function is being called before the test can finish. Here are the error logs:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure
"done()" is called; if returning a Promise, ensure it resolves.
{ NoSuchSessionError: no such session (Driver info:
chromedriver=2.36.540469
(1881fd7f8641508feb5166b7cae561d87723cfa8),platform=Mac OS X 10.13.3
x86_64)
at Object.checkLegacyResponse (/Users/me./myproject/node_modules/selenium-webdriver/lib/error.js:585:15)
at parseHttpResponse (/Users/me./myproject/node_modules/selenium-webdriver/lib/http.js:533:13)
at Executor.execute (/Users/me./myproject/node_modules/selenium-webdriver/lib/http.js:468:26)
at
at process._tickCallback (internal/process/next_tick.js:188:7) name: 'NoSuchSessionError', remoteStacktrace: '' }
If I remove my after() function, I still get
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure
"done()" is called; if returning a Promise, ensure it resolves.
but, my console.log shows that my element has been found.
If I then try making after() async, like this:
after(async function () {
await driver.quit()
})
I get the same error as the first one.
It is also important to note that I have read that I don't have to use done() when I am doing async/await. So what in the world is that all about? And even if I did, I keep getting the same error.
How do I solve this? It seems like everything is in order, but I can't seem to appropriately have the tests run through without running into each other.
Instead of using:
await driver.wait(until.elementIsVisible(driver.findElement(By.className('element'))), 1000)
try:
await driver.wait(until.elementLocated(By.className('element'))).isDisplayed()