dot
dot

Reputation: 15660

how to call another async function after the first one completes?

I'm just started to learn about how Javascript promises work. I understand the concepts, and some code. But in the snippet below, i don't see the "then()" or "catch()" so I'm not too sure how to modify it so that when it's successful, i call another async method.

const gulp = require('gulp');
const build = require('@microsoft/sp-build-web');
const spsync = require('gulp-spsync-creds').sync;
const sppkgDeploy = require('node-sppkg-deploy');

build.task("deploySharepointApps", {
  execute: async () => {
    const appList = require("./config/apps.json");

    if (!pluginList) {
      return;
    }
    
    for (const { name, sites } of appList.apps) {
      const folderLocation = `./apps/${name}`;

      for (const site of sites) {
   
        await new Promise((resolve) => {
          gulp
            .src(folderLocation)
            .pipe(
              spsync({
                username: creds.username,
                password: creds.password,
                site: coreOptions.siteUrl + site,
                libraryPath: coreOptions.appCatalog,
                publish: true,
              })
            )
            .on("finish", resolve);
        });
      }
    }
  },
});

As this code loops and copies / uploads an app, I want to then deploy the same application using this code:

  return sppkgDeploy.deploy({
    username: uname, 
    password: pswd,
    absoluteUrl: catURL
    filename: filename,
    skipFeatureDeployment: false,
    verbose: true
  });

Can you point me in the right direction on how to "chain" this? Right now I'm experimenting to see if i can add a .then right after the .on.

EDIT 1

I tried to change the inner for loop like this:

        for (const site of sites) {
            // Here await each gulp pipeline to finish before moving on to the next.
            await new Promise((resolve) => {
              gulp
                .src(folderLocation)
                .pipe(
                  spsync({
                    username: uname,
                    password: pswd,
                    site: coreOptions.siteUrl + site,
                    libraryPath: coreOptions.appCatalog,
                    publish: true,
                  })
                )
                .on("finish", resolve);
            });

            await sppkgDeploy.deploy({
              username: uname,
              password: pswd,
              absoluteUrl: catURL,
              filename: name,
              skipFeatureDeployment: false,
              verbose: true,
            });
        }//end for

It bombs with an error:

dev3:spfx-plugins admin$ gulp upload-sequential
Build target: DEBUG
[16:00:41] Using gulpfile /src/spfx-plugins/gulpfile.js
[16:00:41] Starting gulp
[16:00:41] Starting 'upload-sequential'...
[16:00:41] Uploading test.sppkg
[16:00:42] Upload successful 1679ms
[16:00:43] Published file 403ms
(node:69005) UnhandledPromiseRejectionWarning: Failed to call the API URL: https://<mydomain>.sharepoint.com/sites/<mysite>/AppCatalog/_api/site?$select=Id
(node:69005) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:69005) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
About to exit with code: 0
Process terminated before summary could be written, possible error in async code not continuing!
Trying to exit with exit code 1

So I wrapped added a try/catch but I never end up in the catch. Here's what the current code looks like:

build.task("deploySharepointApps", {
  execute: async () => {
    try 
    {
       const appList = require("./config/apps.json");

       for (const { name, sites } of pluginList.plugins) {
         for (const site of sites) {
         [original code]

          await sppkgDeploy.deploy({
             username: uname,
             password: pswd,
             absoluteUrl: catURL,
             filename: name,
             skipFeatureDeployment: false,
             verbose: true,
           });
          } // end for
        } //end for
    } catch (error) {
        console.log('inside the error handler');
    }

Upvotes: 2

Views: 387

Answers (1)

tam.teixeira
tam.teixeira

Reputation: 863

Edit 1: I think there is some error on the stream (pipe) part, so added error handling on that part, from your log i see that at least 1 app has been published with success, so i believe the reject part will allow you to check further errors. The UnhandledPromiseRejectionWarning should been fixed with that reject part.

        for (const site of sites) {
            // Here await each gulp pipeline to finish before moving on to the next.
            await new Promise((resolve, reject) => {
              gulp
                .src(folderLocation)
                .pipe(
                  spsync({
                    username: uname,
                    password: pswd,
                    site: coreOptions.siteUrl + site,
                    libraryPath: coreOptions.appCatalog,
                    publish: true,
                  })
                )
                .on('error', 
                   (error) =>  { 
                      console.log('spsync error:', error);
                      reject(error);
                 }) 
                .on("finish", resolve());
            });

            await sppkgDeploy.deploy({
              username: uname,
              password: pswd,
              absoluteUrl: catURL,
              filename: name,
              skipFeatureDeployment: false,
              verbose: true,
            });
        }//end for

I would do it using await since you're inside a block marked as async, and not using the then/catch. When you call await you're only executing the next line of code when that await code resolves, or if it rejects it goes to the catch block as in below:


    const gulp = require("gulp");
    const build = require("@microsoft/sp-build-web");
    const spsync = require("gulp-spsync-creds").sync;
    const sppkgDeploy = require("node-sppkg-deploy");

    build.task("deploySharepointApps", {
      execute: async () => {
        const appList = require("./config/apps.json");

        if (!pluginList) {
          return;
        }

        try {
          for (const { name, sites } of appList.apps) {
            const folderLocation = `./apps/${name}`;

            for (const site of sites) {
              await new Promise((resolve) => {
                gulp
                  .src(folderLocation)
                  .pipe(
                    spsync({
                      username: creds.username,
                      password: creds.password,
                      site: coreOptions.siteUrl + site,
                      libraryPath: coreOptions.appCatalog,
                      publish: true,
                    })
                  ) // Notice the resolve() here
                  .on("finish", resolve());
              });
            }
          }

          await sppkgDeploy.deploy({
            username: uname,
            password: pswd,
            absoluteUrl: catURL,
            filename: filename,
            skipFeatureDeployment: false,
            verbose: true,
          });
        } catch (error) {
          console.log(err);
        }
      },
    });

Notice that since you're using await new Promise(...), the sppkgDeploy.deploy(...) will be the last thing to be executed. And if await new Promise(...) throws an error, you'll be hitting the catch block and not running the code to deploy

Upvotes: 1

Related Questions