饕餮饗食
饕餮饗食

Reputation: 105

How should i run a async function in sync function in NodeJS?

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?

Upvotes: 2

Views: 6220

Answers (2)

g.p
g.p

Reputation: 370

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

Upvotes: 0

jfriend00
jfriend00

Reputation: 707916

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.

Upvotes: 1

Related Questions