簡體   English   中英

等待函數完成,然后在Node JS中觸發下一個函數

[英]Wait for a function to finish before firing the next in Node JS

我已經完成了以下任務:

// default task, runs through all primary tasks
gulp.task("default", ["media", "scripts", "styles", "html"], function () {
    // notify that task is complete
    gulp.src("gulpfile.js")
        .pipe(plugins.gulpif(ran_tasks.length, plugins.notify({title: "Success!", message: ran_tasks.length + " task" + (ran_tasks.length > 1 ? "s" : "") + " complete! [" + ran_tasks.join(", ") + "]", onLast: true})));

    // trigger FTP task if FTP flag is passed
    if (plugins.argv.ftp) {
        config_module.config(gulp, plugins, settings);
        ftp_module.upload(gulp, plugins, settings, ran_tasks, on_error);
    }

    // reset ran_tasks array
    ran_tasks.length = 0;
});

除了FTP位,其他都很好用。 在觸發ftp_module.upload()之前,我需要config_module.config()完成。 我曾嘗試通過回調設置Promise和匿名函數,但是這些解決方案均無效。 FTP功能會在配置前不斷觸發。

如何使ftp_module.upload()函數在觸發之前等待config_module.config()完成?


編輯:這是我嘗試過的諾言,仍然無法正常工作:

new Promise(function (resolve) {
    config_module.config(gulp, plugins, settings);
    resolve();
}).then(function () {
    ftp_module.upload(gulp, plugins, settings, ran_tasks, on_error);
});

編輯:我希望不必發布modules_config.config()代碼,因為它很長,但是我認為有必要繼續前進:

module.exports = {
    // config task, generate configuration file for FTP & BrowserSync and prompt dev for input
    config(gulp, plugins, settings) {
        // generate settings.json and start other functions
        const generate_config = function (callback) {
            return plugins.fs.stat("./settings.json", function (err) {
                if (err !== null) {
                    const json_data =
                    `{
                        "ftp": {
                            "dev": {
                                "hostname": "",
                                "port":     "21",
                                "mode":     "ftp",
                                "username": "",
                                "password": "",
                                "path":     ""
                            },
                            "dist": {
                                "hostname": "",
                                "port":     "21",
                                "mode":     "ftp",
                                "username": "",
                                "password": "",
                                "path":     ""
                            }
                        },
                        "browsersync": {
                            "dev": {
                                "proxy":  "",
                                "port":   "",
                                "open":   "",
                                "notify": ""
                            },
                            "dist": {
                                "proxy":  "",
                                "port":   "",
                                "open":   "",
                                "notify": ""
                            }
                        }
                    }`;

                    plugins.fs.writeFile("./settings.json", json_data, "utf8", function () {
                        callback();
                    });
                } else if (typeof callback === "function") {
                    callback();
                }
            });
        };

        // configue JSON data
        const configure_json = function (namespace, options, env, callback) {
            const prompts = [];

            // construct the prompts
            Object.keys(options).forEach(option => {
                const properties = options[option];

                // construct the prompt
                const prompt     = {
                    name:    option,
                    message: namespace + " " + option + ": ",
                };

                // construct the prompt
                Object.keys(properties).forEach(property => {
                    prompt[property] = properties[property];
                });

                // put the prompt in the array
                prompts.push(prompt);
            });

            // prompt the user
            return gulp.src("./settings.json")
                .pipe(plugins.prompt.prompt(prompts, function (res) {
                    // open settings.json
                    const file = plugins.json.read("./settings.json");

                    // update data in JSON
                    Object.keys(options).forEach(option => {
                        file.set(namespace + "." + env + "." + option, res[option]);
                        settings[namespace][option] = res[option];
                    });

                    // write updated file contents
                    file.writeSync();

                    if (typeof callback === "function") {
                        callback();
                    }
                }));
        };

        return new Promise (function (resolve) {
            // get the target environment
            const env = plugins.argv.dist ? "dist" : "dev";

            // generate settings.json
            generate_config(function () {
                // read browsersync settings from settings.json
                settings.browsersync.proxy  = plugins.json.read("./settings.json").get("browsersync." + env + ".proxy");
                settings.browsersync.port   = plugins.json.read("./settings.json").get("browsersync." + env + ".port");
                settings.browsersync.open   = plugins.json.read("./settings.json").get("browsersync." + env + ".open");
                settings.browsersync.notify = plugins.json.read("./settings.json").get("browsersync." + env + ".notify");

                // read FTP settingss from settings.json
                settings.ftp.host = plugins.json.read("./settings.json").get("ftp." + env + ".hostname");
                settings.ftp.port = plugins.json.read("./settings.json").get("ftp." + env + ".port");
                settings.ftp.mode = plugins.json.read("./settings.json").get("ftp." + env + ".mode");
                settings.ftp.user = plugins.json.read("./settings.json").get("ftp." + env + ".username");
                settings.ftp.pass = plugins.json.read("./settings.json").get("ftp." + env + ".password");
                settings.ftp.path = plugins.json.read("./settings.json").get("ftp." + env + ".path");

                // configure FTP credentials
                configure_json("ftp", {
                    hostname: {
                        default: settings.ftp.host,
                        type:    "input",
                    },
                    port: {
                        default: settings.ftp.port,
                        type:    "input",
                    },
                    mode: {
                        default: settings.ftp.mode === "ftp" ? 0 : settings.ftp.mode === "tls" ? 1 : settings.ftp.mode === "sftp" ? 2 : 0,
                        type:    "list",
                        choices: ["ftp", "tls", "sftp"],
                    },
                    username: {
                        default: settings.ftp.user,
                        type:    "input",
                    },
                    password: {
                        default: settings.ftp.pass,
                        type:    "password",
                    },
                    path: {
                        default: settings.ftp.path,
                        type:    "input",
                    },
                }, env, function () {
                    // configure BrowserSync settings
                    configure_json("browsersync", {
                        proxy: {
                            default: settings.browsersync.proxy === "" ? "localhost" : settings.browsersync.proxy,
                            type: "input",
                        },
                        port: {
                            default: settings.browsersync.port === "" ? "8080" : settings.browsersync.port,
                            type: "input",
                        },
                        open: {
                            default: settings.browsersync.open === "" ? "external" : settings.browsersync.open,
                            type: "input",
                        },
                        notify: {
                            default: settings.browsersync.open === "" ? "false" : settings.browsersync.open,
                            type: "input",
                        },
                    }, env, function () {
                        // resolve the promise
                        resolve();
                    });
                });
            });
        });
    }
};

如您所見,它正在返回一個Promise,但是無論出於什么原因,我仍然無法在它之后觸發FTP任務。

您已經對問題有一個可能的答案:諾言。

問題是您做錯了。

在編輯中發布的代碼(帶有promise)中,您正在調用config_module方法(似乎是異步的),然后立即解析promise。 在這種情況下,因為該方法是異步的,所以在對config方法進行處理之前,promise會被解決,從而導致不良行為。

正確的方法是您應使config_module方法調用本身正確無誤。 這樣,您僅在完全執行方法后才“解決”承諾。

由於您未發布config_module方法的代碼,因此很難說。 但是,您應該在其中創建一個Promise,然后僅在完成計算后再解決它。 所以你可以這樣:

config_module.config(gulp, plugins, settings)
    .then(function () { 
        ftp_module.upload(gulp, plugins, settings, ran_tasks, on_error);
    });

編輯:

之后您發布您的config_module代碼,這是比較容易看到,唯一缺少的是使用由配置方法返回的承諾來運行。然后塊內的ftp_module.upload

 new Promise(function (resolve) { config_module.config(gulp, plugins, settings, ()=>{promise.resolve()}); }).then(function () { ftp_module.upload(gulp, plugins, settings, ran_tasks, on_error); }); config_module.config = (gulp, plugins, settings, doneCallback){ //...do stuff doneCallback() } 

一種方法,

這樣做的另一種方式是必須鏈接返回的函數會自己承諾,即可以使用像這樣的函數來鏈接它們:

 var pipeline = (tasks, arg) => { return tasks.reduce((promise, fn) => { return promise.then(fn) }, Promise.resolve(arg)) } 

基本上,當鏈式函數解析時,它會承諾使用傳遞給您的解析數據來調用下一個。

您必須return諾言以使其同步

但是為此,您的函數必須返回一個promise (例如config_module.configftp_module.upload 如果沒有promise返回函數,則可以使用promisifycallback函數轉換為promise

new Promise(function () {
    var _config = Promise.promisify(config_module.config);  //make your callback a Promise
    return _config(gulp, plugins, settings);    //now call the function, and return its result (which is a Promise now)
}).then(function () {
    var _upload = Promise.promisify(ftp_module.upload);
    return _upload(gulp, plugins, settings, ran_tasks, on_error);
});

我建議您使用Async 它是一個功能強大的模塊,可幫助您構建應用程序並簡化控制流程。

Async提供的功能之一是series ,可讓您逐個調用功能(即,第二個功能要等到第一個功能完成后才能運行)。

async.series(
   [
      function(callback) {
         // ...
         config_module.config();
         // do some more stuff if needed ...
         callback(null, 'one');
      },
      function(callback) {
         // ...
         ftp_module.upload();
         // do some more more stuff if needed ...
         callback(null, 'two');
      }
   ],
   // optional callback
   function(err, results) {
     // results is now equal to ['one', 'two']
   }
);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM