Why does setTimeout behave this way in my stream implementation? - javascript

The final line of this code successfully calls the _read method of a custom Duplex stream in node.
const timeContext = new TimeContext(sampleRate);
const input = new InputStream(timeContext); // Stream.Readable
const throttle = new Throttle(sampleRate); // Stream.Transform
const stackSource = [];
const stack = new StackStream(stackSource); // Stream.Duplex
input.pipe(throttle).pipe(stack);
stack.read(); // This will call the _read method of StackStream
Adding setTimeout to delay the stream.read() call, setTimeout's callback does NOT get called:
const timeContext = new TimeContext(sampleRate);
const input = new InputStream(timeContext); // Stream.Readable
const throttle = new Throttle(sampleRate); // Stream.Transform
const stackSource = [];
const stack = new StackStream(stackSource); // Stack.Duplex
input.pipe(throttle).pipe(stack);
setTimeout(() => {
stack.read(); // This callback never gets called
}, 1000);

It definitely does get called but something else is erroring
setTimeout(() => {
console.log('We got here');
stack.read(); // This is what is crashing in your code
console.log('We don\'t get here');
}, 1000);
It is just not behaving as you expect because some other error is occurring. Look in the console to see what errors are raised.

Looks like, read() function is a local property of the stack object and the setTimeout is not able to see this local property of stack object. That's why it's behaving in such a way.
Refer this solution for reference,
https://stackoverflow.com/a/4536268/10371717

Related

Call method on object also do async operation before

i'm using a library that return an object with multiple keys and methods to use, one of the key of this object is accessToken.
accessToken value must exist before calling any method of this object (otherwise you're not authenticated).
The token is retrieved externally using an async axios function, also this token is only valid for 1 hour, in this case it's okay to get a new token every time you call some function inside it.
I dont' want to recreate the object every time i use this library (i'm using this library multiple times).
So far based on few articles i found online i did this:
const force = require('jsforce')
const { SFAuth } = require('./auth')
const common = require('../common')
class JSForce {
constructor (connection) {
return connection
}
static async Connect () {
const token = await SFAuth.getToken()
const connection = new force.Connection({
instanceUrl: common.SALESFORCE_URL,
accessToken: token
})
return new JSForce(connection)
}
}
const start = async () => {
const res = await JSForce.Connect()
console.log(res)
}
start()
If i try to do JSForce.Connect().sobject('Account') i get an error saying sobject is not a function.
It works if first i save JSFORCE.Connect() in a new instance and then i use this instance.sobject() but i can't do it every time i need to use it.
How would you solve this?
Thanks!!
Problem is field sobject will only come once you have JSForce connection successful. First we need to make sure we have that and we can save in variable. We will only call JSForce if we don't have instance already.
Declare a global variable in file.
let instance: <any>
// This method will return instance always if we dont have
const getInstance = async () => {
if (!instance) {
instance = await JSForce.Connect();
}
return instance;
};
const start = async () => {
const res = await getInstance().sobject('Account');
console.log(res);
}
start();

Understanding factory error handler step-by-step

i'm reading and learning about promises/async/await.
I'm a little stuck trying to understand step by step an error handling method that i already seen a couple of times, its a factory function approach for dealing with errors when creating promises.
Code with comments (questions below)
const myPromise = new Promise((resolve, reject)=>
setTimeout(()=> console.log('ERROR MESSAGE'),1000))
// async / await with error handler factory
const testPromise = async () => {
var data = await myPromise;
console.log(data)
}
// this is where i get stuck
const errorHandlerBig = function(fn){ // (1)
return function(...parameters) { // (2)
return fn(...parameters).catch(function(err){ // (3)
console.error('Caught in Example 3:', err)
})
}
}
errorHandlerBig(testPromise)();
Takes testPromise as argument
I debugged this and parameters content
is [] (empty), when trying to assign a param to testPromise =
async(paramName) => .... i can't work with it inside that function.
what is it trying to spread?
this is translated as testPromise(...params from previous step) i assume
Why is this chain of function calling-inside another function necesary?
Following with item (2), when trying to pass a value to paramName, it doesn't get printed on the console either!:
const testPromise = async (paramName) => {
var data = await myPromise;
console.log(data, paramName)
}
const errorHandlerBig = function(fn){...}
errorHandlerBig(testPromise)('RandomValue')
Thank you everyone in advance!
errorHandlerBig is taking a function and wrapping it in its own error handling.
From the outside in, it:
Takes a function(1) as a parameter.
Creates and returns a new function (2) that accepts any number of parameters.
In function 2, calls function 1 using the parameters passed to function 2, and tries to catch any errors generated.
Since errorHandlerBig is passing the parameters to fn, you would need testPromise to accept the parameters and log them if you expected them to appear in your console. Or you could throw them as an error in testPromise.
As written, this isn't very useful, but it could be useful if you needed to make the same async process run more than once by saving the function returned by errorHandlerBig in a variable and calling that with different parameters, or if you wanted to use the same error handling behavior for multiple asynchronous processes.
const throwThings = async (throwWhat) => {
throw new Error(throwWhat);
}
const happyFunTimes = async (activity) => {
console.log("I'm having fun");
await setTimeout(() => console.log(`jumping on a ${activity}`), 1000);
}
const errorHandlerBig = function(fn){ // (1)
return function(...parameters) { // (2)
return fn(...parameters).catch(function(err){ // (3)
console.error('Caught in Example 3:', err.toString())
});
}
}
document.getElementById(":)").addEventListener("click", () => errorHandlerBig(happyFunTimes)("bananas"));
document.getElementById(">:(").addEventListener("click", () => errorHandlerBig(throwThings)("bananas"));
<button id=":)">Fun times</button>
<button id=">:(">Throw</button>

Stop long running javascript functions on the browser

My question has two parts
I want to terminate a function if it runs more than 200ms and return a default value. I tried to experiment with the concept of Promise.race but that did not yield the desired result
I want to identify if the function has an infinite loop similiar to how JSFiddle or Codepen is able to exit when someone uses an infinite loop without freezing the browser or overloading the CPU
Is it possible
Yeah, you can do that, here's a general-purpose script I wrote as proof of concept. It dynamically creates a web worker and uses it in the same way other languages have threads. However, if you're just trying to kill an active XHR or Fetch call, there are built-in methods for doing that.
/**
* Run some code in it's own thread
* #params - Any parameters you want to be passed into the thread
* #param - The last parameter must be a function that will run in it's own thread
* #returns - An promise-like object with a `then`, `catch`, and `abort` method
*/
function Thread() {
var worker;
const promise = new Promise((resolve, reject) => {
var args = Array.from(arguments);
var func = args.pop();
if (typeof func !== "function") throw new Error("Invalid function");
var fstr = func.toString();
var mainBody = fstr.substring(fstr.indexOf("{") + 1, fstr.lastIndexOf("}"));
var paramNames = fstr.substring(fstr.indexOf("(") + 1, fstr.indexOf(")")).split(",").map(p => p.trim());
var doneFunct = paramNames.pop();
if (paramNames.length !== args.length) throw new Error("Invalid number of arguments.");
var workerStr = `var ${doneFunct} = function(){
var args = Array.from(arguments);
postMessage(args);
};
self.onmessage = function(d){
var [${paramNames.join(", ")}] = d.data;
${mainBody}
};`;
var blob = new Blob([workerStr], {
type: 'application/javascript'
});
worker = new Worker(URL.createObjectURL(blob));
worker.onerror = reject;
worker.onmessage = (d) => {
resolve(...d.data);
worker.terminate();
};
worker.postMessage(args);
});
return {
then: (...params)=>promise.then(...params),
catch: (...params)=>promise.catch(...params),
abort: ()=>worker.terminate()
}
}
////////////////////////
//// EXAMPLE USAGE /////
////////////////////////
// the thread will take 2 seconds to execute
// and then log the result
var myThread = new Thread("this is a message", 2, function(message, delaySeconds, exit) {
setTimeout(() => {
exit(message.split('').reverse().join(''));
}, delaySeconds * 1000);
});
myThread.then(result => console.log(result));
// the thread will take 2 seconds to execute
// but we will cancel it after one second
var myThread = new Thread("this is a message", 2, function(message, delaySeconds, exit) {
setTimeout(() => {
exit(message.split('').reverse().join(''));
}, delaySeconds * 1000);
});
setTimeout(()=>{
myThread.abort();
}, 1000);
If you have access to the function you can add a time check inside the loop that runs for long time and return when you reach time limit (simplest way, most compatible way).
If you don't know what the function is doing or can't modify it, you can try wrapping it inside a Web worker. If you start the long running js inside the worker, you can then .terminate() it when it reaches the timeout
Also, It is impossible to determine if something contains an infinite loop without executing it

How to let a webworker do multiple tasks simultaneously?

I am trying to let a Web-Worker manage its state, meanwhile serving multiple async requests.
worker.ts file
let a =0; //this is my worker's state
let worker=self as unknown as Worker;
worker.onmessage =(e)=>{
console.log("Rec msg", e.data);
if(e.data === "+1"){
setTimeout(()=>{
a=a+1;
worker.postMessage(a);
},3000);
}else if(e.data=== "+2"){
setTimeout(()=>{
a=a+2;
worker.postMessage(a);
},1000)
}
}
And this is my main file: main.ts
let w =new Worker("./worker.ts", {type: "module"})
let wf =async (op: string)=>{
w.postMessage(op);
return new Promise<any>((res,rej)=>{
w.onmessage=res;
});
}
(async()=>{
let f1 = await wf("+1");
console.log("f1",f1.data);
})();
(async()=>{
let f2 = await wf("+2");
console.log("f2",f2.data);
})()
Only f2 is returned , and f1 is lost.
I have used timeouts to simulate say some async task done by worker themselves.
How do I receive both f1 and f2?
Your problem is that you are trying to take an event based API and use it as a Promise based one, but events may fire multiple times, while Promise should resolve only once.
The communication between the Worker and the main thread works by sending and receiving messages, but there is by default no one-to-one relation between these messages. Both ends of the communication (ports) will simply stack incoming messages, and handle them sequentially, when they'll get time.
In your code, the main thread's worker.onmessage handler of f1 has been overwritten by the second call f2 synchronously (one microtask later, but that's still synchronous for our matter).
You could attach your event using the addEventListener method, at least this way it wouldn't be overwritten. But even then, when the first message event will fire on worker, both handlers will think it's there own message that did arrive, while in fact it was the one of f2. so that's not what you need...
What you need is to set up a protocol of communication which would allow both ends to identify each task. You could for instance wrap all your tasks' data with an object containing a .UIID member, be sure both ends wraps their message this way, and then from main thread check that UUID to resolve the appropriate Promise.
But that can become a bit complicated to implement and to use.
My personal favorite way is to create a new MessageChannel per task. If you don't know this API, I invite you to read this answer of mine explaining the basics.
Since we are sure the only one message that will come through this MessageChannel is the response from the Worker to the one task we sent to it, we can await it just like a Promise.
All we have to do, is to make sure that in the Worker thread we respond through the transferred port instead of the global scope.
const url = getWorkerURL();
const worker = new Worker(url)
const workerFunc = (op) => {
// we create a new MessageChannel
const channel = new MessageChannel();
// we transfer one of its ports to the Worker thread
worker.postMessage(op, [channel.port1]);
return new Promise((res,rej) => {
// we listen for a message from the remaining port of our MessageChannel
channel.port2.onmessage = (evt) => res(evt.data);
});
}
(async () => {
const f1 = await workerFunc("+1");
console.log("f1", f1);
})();
(async () => {
const f2 = await workerFunc("+2");
console.log("f2", f2);
})()
// SO only
function getWorkerURL() {
const elem = document.querySelector( '[type="worker-script"]' );
const script = elem.textContent;
const blob = new Blob( [script], { type: "text/javascript" } );
return URL.createObjectURL( blob );
}
<script type="worker-script">
let a = 0;
const worker = self;
worker.onmessage = (evt) => {
const port = evt.ports[0]; // this is where we will respond
if (evt.data === "+1") {
setTimeout(() => {
a = a + 1;
// we respond through the 'port'
port.postMessage(a);
}, 3000);
}
else if (evt.data === "+2") {
setTimeout(() => {
a = a + 2;
// we respond through the 'port'
port.postMessage(a);
}, 1000)
}
};
</script>

Nodejs running function on background

I’ve nodes program which I need to run two function in the beginning of the program
And later on access the function results, currently with await each function at a time this works,
However in order to save a time and not waiting to GetService and GetProcess as I need the data later on in the project
It takes about 4 seconds to get this data and I want to run it on the background as I don’t need the results immediately,
How I can do it in node js, If I run promise.all It would wait until the getService and getProcess and then go to rest of the program.
an example
function main() {
//I want to run this both function in background to save time
let service = await GetServices();
this.process = await GetProcess();
…..//Here additional code is running
//let say that after 30 second this code is called
Let users = GetUser(service);
Let users = GetAdress(this.process);
}
im actually running yeoman generator
https://yeoman.io/authoring/
https://yeoman.io/authoring/user-interactions.html
export default class myGenerator extends Generator {
//here I want run those function in background to save time as the prompt to the user takes some time (lets say user have many questions...)
async initializing() {
let service = await GetServices();
this.process = await GetProcess();
}
async prompting() {
const answers = await this.prompt([
{
type: "input",
name: "name",
message: "Your project name",
default: this.appname // Default to current folder name
},
{
type: "confirm",
name: "list",
choises: this.process //here I need to data from the function running in background
}
]);
}
Let's assume that getServices() may take 3 seconds and getProcess() may take 4 seconds, so if you run these both functions at the same time you will be returned in total 4 seconds with the return values from both promises.
You can execute the code while this process is running in the background there will be a callback when the promises resolved, your late functions will be called at this stage.
Check the below simple example;
let service;
let process;
function main() {
// Both functions will execute in background
Promise.all([getServices(), getProcess()]).then((val) => {
service = val[0];
process = val[1];
console.log(service, process);
// Aafter completed this code will be called
// let users = GetUser(service);
// let users = GetAdress(process);
console.log('I am called after all promises completed.')
});
// Current example.
// let service = await GetServices();
// this.process = await GetProcess();
/* Code blocks.. */
console.log('Code will execute without delay...')
}
function getServices() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("service is returned")
}, 3000);
});
}
function getProcess() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("process is returned")
}, 4000);
});
}
main();
You can start the asynchronous operation but not await it yet:
function suppressUnhandledRejections(p) {
p.catch(() => {});
return p;
}
async function main() {
// We have to suppress unhandled rejections on these promises. If they become
// rejected before we await them later, we'd get a warning otherwise.
const servicePromise = suppressUnhandledRejections(GetServices());
this.processPromise = suppressUnhandledRejections(GetProcess());
// Do other stuff
const service = await servicePromise;
const process = await this.processPromise;
}
Also consider using Promise.all() which returns a promise for the completion of all promises passed to it.
async function main() {
const [ services, process, somethingElse ] = await Promise.all([
GetServices(),
GetProcess(),
SomeOtherAsyncOperation(),
]);
// Use the results.
}
To do what who you need, you have to understand the event loop.
Nodejs is designed to work in a single thread unlike languages like go, however nodejs handle proccess on different threads. so you can use nextTick () to add a new event to the main thread and it will be executed at the end of the whole block.
function main() {
//I want to run this both function in background to save time
let service = await GetServices();
this.process = await GetProcess();
…..//Here additional code is running
//Let say that after 30 second this code is called
Let users = GetUser(service);
Let users = GetAdr(this.process);
}
function someFunction(){
// do something...
}
main();
process.nextTick(someFunction());// happens after all main () processes are terminated...

Categories

Resources