[英]Wait for download method to finish before running next .then - 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.config
和ftp_module.upload
) 。 如果沒有promise返回函數,則可以使用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);
});
我建議您使用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.