This question already has answers here:
Call An Asynchronous Javascript Function Synchronously
(13 answers)
Closed last month.
I am currently developing a plugin for eslint. I have encountered the following problem.
I want to make hot changes to the configuration file, so we are required to make an Http request to get the JSON file with the configuration.
As for the context execution when reading the package.json, and traversing the scripts, when adding async/await, it executes in node the code, but does not return the context response from the context object.
If I do it with callbacks exactly the same thing happens. I leave you the code so that you have a visual idea of the problem.
With Promises using then(), catch(), doesnt works too.
I think that what I am asking for in the JavaScript world is not possible, but by asking I don't lose anything. I understand that the functions like execSync, are native inside the C core written in JavaScript, and that's why they can be executed synchronously.
Thanks and greetings.
'use strict';
const { readFileSync } = require("fs");
//------------------------------------------------------------------------------
// Meta Definition
//------------------------------------------------------------------------------
const meta = {
type: 'problem',
docs: {
description: `Rule to don't allow changes in scope scripts of package.json`,
category: 'Possible Errors'
},
schema: [
{
type: 'object',
properties: {
alternatives: {
type: 'object',
patternProperties: {
'^.+$': { type: 'string' }
}
}
},
additionalProperties: false
}
]
};
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
const TEST_CONTENT = 'jest';
const isPackageJsonFile = filePath => filePath.includes('package.json');
module.exports = {
meta,
create: (context) => {
return {
'Program:exit': async node => {
if (!isPackageJsonFile(context.getFilename())) {
return;
}
const packageJsonRaw = readFileSync(context.getFilename(), 'utf8');
const packageJson = JSON.parse(packageJsonRaw );
// Peticion async / await
const testScript = await httpRequest.getJSONFromURL().test || TEST_CONTENT;
if (!packageJson.scripts || packageJson.scripts.test !== TEST_CONTENT) {
context.report({
message: `Dont allow changes on script "scripts.test" of package.json`,
node
});
}
}
}
}
};
A way to be able to return the result of the http request, like fileReadSync but without callbacks because it doesn't work, is it possible, I can't think how to do it.
The implementation that I have made at the moment, I make use of child_process with curl, with an execSync, and with that I have managed to make it work, but the truth is that I am not convinced at all by this implementation.
try this simple way of promising
async function doB(){
try{
const res = await CertainPromise()
return res.json();//something
}catch(e){}
}
This should actually work;
Related
I am trying to modify the behaviour of the "passwordless" strapi plugin so that it would generate the verification code only with digits. So for this I need to override a function createToken in the plugin's service.
I created a folder with the name of the plugin inside extensions folder as specified in Strapi docs. And inside this folder(strapi-plugin-passwordless) I created a file strapi-server.js in which I export a function:
module.exports = (plugin) => {
plugin.services.passwordless.createToken = async (email, context) => {
const settings = await this.settings();
const tokensService = strapi.query("plugin::passwordless.token");
tokensService.update({ where: { email }, data: { is_active: false } });
const body = customAlphabet("1234567890", 6);
const tokenInfo = {
email,
body,
context: JSON.stringify(context),
};
return tokensService.create({ data: tokenInfo });
};
return plugin;
};
The only difference between original createToken function the custom one is that the variable body is in the form of 6 digits.
However, Strapi doesn't run this function, instead it runs the original one on node_modules?
What may I possibly be doing wrong ?
I have a vue project that use CDN to getting it libs for running. Now I want to add a integrity property on the script label to verify the script it pull from CDN. And I want the code automatic generate the hash of script and insert is to the dist when i build the project.
I want a some sync function like this:
function integrityWapper ({ css, js }) {
const hash = require('crypto-js').SHA384
const icss = []; const ijs = []
for (const i in css) {
icss.push([css[i], hash(GettingScriptContentFromWeb(css[i]))])
}
for (const i in js) {
ijs.push([js[i], hash(GettingScriptContentFromWeb(js[i]))])
}
return { icss, ijs }
}
Obviously, this function cannot be async cause i am trying to generate config for vue.config.js, so the GettingScriptContentFromWeb function must also be sync.
Is there a way turn call async function(i mean axios.get) in sync function and wait it to finish?
Update:
No, i can't just rewrite the upstream cause i need export the result in vue.config.js, this is some code i currently use:
** vue.config.js **
module.exports = defineConfig({
integrity: true,
pages: {
index: {
entry: 'src/main.ts',
template: 'public/index.html',
filename: 'index.html',
CDN: cdnConfig.use ? cdnConfig.list : null
}
}
})
//cdnConfig.list is like this:
list: {
css: [
[
'https://cdn.bootcdn.net/ajax/libs/element-plus/2.2.13/index.css',
'sha384-WdBufJjVUMBy2e6mTgtUbbYZvZg7vdYW3ijXdfg4jglZAehE17bPFaxNMhFXuH1Z'
]
],
js: [
[
'https://cdn.bootcdn.net/ajax/libs/vue/3.2.37/vue.global.prod.min.js',
'sha384-MB7auY3xTNj+3Hk53DrKFyXN7Djh50mLDesxCDPr4XENv8gK06a3RqhmkXBfcPFh'
]
]
}
Or can somebody tell me how can i rewrite the part that vue and webpack read these config?
Should i just write this script in a other file and i run it before vue-cli-service build in npm run build, or i try to use package like deasync or sync-kit?
Is there a way turn call async function(i mean axios.get) in sync function and wait it to finish?
No, there is not. axios.get() is asynchronous and you cannot get its result synchronously.
You will have to rewrite your code to use an asynchronous design. Probably, GettingScriptContentFromWeb() needs to return a promise and integrityWrapper() needs to use that promise and also needs to return a promise. The caller of integrityWrapper() then needs to use .then() or await on the promise that integrityWrapper() will return to get the resolved value.
For example, if you changed GettingScriptContentFromWeb() to return a promise that resolves to it's value, then you could do this:
async function integrityWapper ({ css, js }) {
const hash = require('crypto-js').SHA384
const icss = []; const ijs = []
for (const i in css) {
icss.push([css[i], hash(await GettingScriptContentFromWeb(css[i]))])
}
for (const i in js) {
ijs.push([js[i], hash(await GettingScriptContentFromWeb(js[i]))])
}
return { icss, ijs }
}
integrityWrapper(...).then(result => {
// use the asynchronously retrieved result here
}).catch(err => {
// got some error here
});
P.S. if css or js are arrays, then you should be using for/of to iterate arrays, not for/in. If they are objects, then you can use for/in to iterate their enumerable properties.
As you are dealing with http api's the result is always going to be asynchronous. From the context, i am assuming you want to execute this script when you are building the project, something like yarn dostuff.
This can be achieved like by wrapping the async function in a self executing function
index.js
async function integrityWapper ({ css, js }) {
const hash = require('crypto-js').SHA384
const icss = []; const ijs = []
for (const i in css) {
icss.push([css[i], hash(await GettingScriptContentFromWeb(css[i]))])
}
for (const i in js) {
ijs.push([js[i], hash(await GettingScriptContentFromWeb(js[i]))])
}
return { icss, ijs }
}
const executor = (async ()=>{
await integrityWapper({
css: process.env.CSS,
js: process.env.JS
});
})();
export default executor;
And then add a script in package.json
"scripts": {
"dostuff": "node index.js",
"custom-build": "yarn dostuff && yarn build"
},
Something on the lines of above
Hope i made sense
I am making an app with WebSockets in Node.js. In order to run certain things asynchronously, I wrapped some async code in an async function and then ran it.
However, the issue is that whenever this portion is ran, the code throws an error that call.createTransport is not a function. This function is clearly defined in the Call class and works when I call it outside of this context.
I proceeded to log the call and found that before running the async function, the call object was an instance of Call, but inside the async function it is a regular JavaScript object, with the properties but not the methods defined.
I am completely stuck on this issue. I am running Node.js 16 LTS.
(async (call, produce, consume) => {
let sendTransport;
if (produce) {
sendTransport = await call.createTransport();
}
let receiveTransport;
if (consume) {
receiveTransport = await call.createTransport();
}
return { sendTransport, receiveTransport };
})(client.call, produce, consume).then(({ sendTransport, receiveTransport }) => {
callClients.set(sId, {
...client,
produce: true,
sendTransport,
receiveTransport
});
s.send(JSON.stringify({
type: CallEventType.TRANSPORT,
data: {
sendTransport,
receiveTransport
}
}));
});
I am working on a project where I have to read around 3000+ JSON files from an Azure DevOps repository and store their contents in a string which I can use later.
Below is the method I am using to fetch the list of items in my repository. I am not allowed to presume any directory hierarchy so I am setting the recursionLevel parameter to full.
Link to the doc:https://learn.microsoft.com/en-us/javascript/api/azure-devops-extension-api/gitrestclient#getitems-string--string--string--versioncontrolrecursiontype--boolean--boolean--boolean--boolean--gitversiondescriptor-
function getItems(repositoryId: string, project?: string, scopePath?: string, recursionLevel?: VersionControlRecursionType, includeContentMetadata?: boolean, latestProcessedChange?: boolean, download?: boolean, includeLinks?: boolean, versionDescriptor?: GitVersionDescriptor)
The above function returns a Promise of Git item list from where I can get the relative path of every file from the root of the repository
After getting a list of items I want to read them one by one and store their contents in a string. For that I am using this method:
function getItemText(repositoryId: string, path: string, project?: string, scopePath?: string, recursionLevel?: VersionControlRecursionType, includeContentMetadata?: boolean, latestProcessedChange?: boolean, download?: boolean, versionDescriptor?: GitVersionDescriptor, includeContent?: boolean, resolveLfs?: boolean)
This function is also available in the same link I shared earlier. You have to scroll down a bit.
It returns the content as Promise of string.
My code to read all the files:
AdoClient.getInstance().getItems(this.repoID, this.projectName, this.commonData.inputBranchName).then(data=>{
data.forEach(element => {
if(element.gitObjectType==3)
{
AdoClient.getInstance().getItemText(this.repoID,element.path,this.commonData.inputBranchName).then(element=>{ content.concat(element);
});})});
In the above code:
gitObjectType=3 means a file
The functions getItems() and getItemText() that you see are actually my functions. I wrote a definition to just pass the 3 required parameters. In the AdoClient file I have the original call to the functions using GitRestClient object just as you have in the doc.
This is the originial function call in AdoClient file:
public async getItemText(repoId: string, filePath: string, branchName: string) {
return this.gitClient.then(client => client.getItemText(repoId, filePath, null, null, 'none', false, false, false, {version: branchName, versionOptions: 0, versionType: 0}));
}
public async getItems(repositoryId: string, project: string,branch: string){
return this.gitClient.then(client=>client.getItems(repositoryId, project, "/ServiceGroupRoot/", 'full', true, false, false, true, {version: branch, versionOptions: 0, versionType: 0}));
}
Also please note /ServiceGroupRoot/ is the root directory in my repository.
When I am doing this I am not being able to get all the contents inside the content variable and also Google chrome is showing ERR_INSUFFICIENT_RESOURCES due to 3000+ ajax calls at the same time. This error is not coming in Mozilla tho. But in Mozilla when I am printing the content it shows empty string. What I want is a way to order my execution steps so that I can have all the contents in my content string. Is there a way to run a loop of Promise calls and make them execute one by one? By one by one I mean finish one then start the next one and not load everything at once or is there some other approach I have to follow?
I guess the easiest way to go is by just using a for loop with await:
const work = i => {
return new Promise(resolve => {
setTimeout(() => resolve(i), Math.floor(Math.random() * 100));
});
};
const array = Array(10).fill(0).map((_, i) => i + 1);
// non sequencial
const test_then = () => {
array.forEach(i => {
work(i).then(i => {
console.log(i);
});
});
};
// sequencial
const test_await = async () => {
for (let i = 0; i < array.length; i++) {
console.log(await work(i));
}
};
test_then();
test_await();
There a few critical mistakes in code.
Suggestion to use the traditional for loop so that we can use async await syntax.
I don't know about resources part, but I have pasted a clear code below.
async function main() {
let content = '';
const data = await AdoClient.getInstance().getItems(/* pass params here*/);
for (let i = 0; i < data.length; i++) {
if(data[i].gitObjectType==3){
const result = await AdoClient.getInstance().getItemText(/* pass params here*/);
content.concat(result);
}
}
return content;
} // main close
const c = main();
console.log(c);// your output
Im having some issues when using module.exports inside NodeJS, and I've followed multiple guides, and im almost certain Im doing it right.
I have to scripts, main.js and event.js. Im trying to share a function from main.js to event.js, but its not working. Here is the code:
Main.js
function Scan(){
if(fs.readdirSync('./events/').length === 0){
console.log(colors.yellow('Events Folder Empty, Skipping Scan'))
} else {
var events = fs.readdirSync('./events/').filter(file => file.endsWith('.json'))
for(const file of events){
let rawdata = fs.readFileSync('./events/' + file);
let cJSON = JSON.parse(rawdata);
}
events.sort()
tevent = events[0]
StartAlerter()
}
}
module.exports = { Scan };
Event.js
const main = require('../main')
main.Scan;
This returns the error:
(node:19292) Warning: Accessing non-existent property 'Scan' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
What am I doing wrong?
I discovered that the arrangement had no effect in the error.
I simply changed the way I exported the function from the Main.js
from:
module.exports = { Scan };
to:
exports.Scan = Scan
And in Event.js, I was able to access the file like this
const main = require("./Main.js");
let result = main.Scan();
This solved my problem, I hope it helps another developer 😎
Problem solved, heres what I did differently:
module.exports = { Scan };
Is declared before the Scan function is defined, like so:
module.exports = { Scan };
function Scan(){
//Code
}
Then in event.js, I wrote
const main = require('../main')
As it is now a module, and can be used with the require() function.
Then to execute the funciton in event.js, I write
main.Scan()
To execute it.
better try :
module.exports = Scan;
I am gonna answer it using a simple example, like in this case below:
File A has 3 functions to process database activity: function
addDB, updateDB, and delData;
File B has 2 functions to process User activity on smartphone:
function addHistory, and editHistory;
Function updateDB in file A is calling function editHis in file B, and function editHistory is calling function updateDB in file A. This is what we called circular-dependency. And we need to prevent it by only giving output of state from editHistory and the rest will be processed inside file A.
//ORIGINAL FUNCTIONS which caused CIRCULAR DEPENDENCY
function updateDB() {
//process update function here
//call function in fileB
const history = require("fileB.js");
await history.editHistory(data).then((output) => {
if(output["message"] === "success"){
response = {
state: 1,
message: "success",
};
}
});
return response;
}
//THIS is the WRONG ONE
function editHistory() {
//process function to edit History here
//call function in fileA
const file = require("fileA.js");
await file.updateDB(data).then((output) => { //You should not call it here
if(output["message"] === "success") {
output = {
state: 1,
message: "success",
};
}
});
return output;
}
//==================================================//
//THE FIX
function updateDB() {
//process function here
const history = require("fileB.js");
await history.editHistory(data).then((output) => {
if(output["message"] === "success"){
await updateDB(data).then((output) => {
response = {
state: 1,
message: "success",
};
});
} else {
log("Error");
}
});
return response;
}
function editHistory() {
//process function to edit History here
// No more calling to function inside the file A
output = {
state: 1,
message: "success",
};
return output;
}