我已经完成了这项任务:
// 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位外,哪种方法效果很好。我需要config_module.config()
完成才能触发ftp_module.upload()
。我已经尝试使用回调设置promises和匿名函数,但这些解决方案都不起作用; 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();
});
});
});
});
}
};
正如您所看到的,它正在返回一个承诺,但无论出于何种原因,我仍然无法在其后触发FTP任务。
答案 0 :(得分:3)
您的问题已经有了一个可能的答案:承诺。
问题是你做错了。
在您在编辑中发布的代码(使用promises),您正在调用 config_module 方法(这似乎是异步的)然后您立即解决了承诺。在这种情况下,由于该方法是异步的,因此在完成 config 方法的处理之前会解析promise,从而导致不需要的行为。
正确的方法是你应该宣传 config_module 方法调用本身。这样,只有在完全执行方法后才能“解析”promise。
由于您没有发布其代码,因此很难说 config_module 方法应该如何。但是你应该在那里创建一个promise,然后只在计算完成后才解决它。所以你可以这样:
config_module.config(gulp, plugins, settings)
.then(function () {
ftp_module.upload(gulp, plugins, settings, ran_tasks, on_error);
});
编辑:
发布 config_module 代码后,更容易看到唯一缺少的是使用 config 方法返回的承诺来运行 ftp_module.upload 在 .then 块内
答案 1 :(得分:0)
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()
}
一种方法,
另一种方法是你必须链接的函数返回promises本身,这样你可以使用像这样的函数链接它们:
var pipeline = (tasks, arg) => {
return tasks.reduce((promise, fn) => {
return promise.then(fn)
}, Promise.resolve(arg))
}
基本上,当您的链接函数解析它的承诺时,它会使用您传递的数据调用下一个函数来解析它。
答案 2 :(得分:0)
您必须return
承诺才能同步。
但为此,您的函数必须返回一个承诺(例如config_module.config
和ftp_module.upload
)。如果您没有承诺退回功能,则可以使用promisify将callback
功能转换为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);
});
答案 3 :(得分:0)
我建议你使用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']
}
);