- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有一个 gulp 任务,它循环遍历一个文件夹以查找子文件夹,并根据每个文件夹的内容输出一个 JavaScript 文件。下面是一个更直观的示例。
变成:
这是通过读取 src/assets/scripts
目录的内容,然后对每个文件夹(critical
、legacy
)运行一个循环来实现的>, modern
, service-worker
) 并将每个文件夹的内容发送到与 merge-stream 合并在一起的 Gulp 任务.
所有这一切都很好,除了一旦任务重新合并在一起,我想在编译成功时触发通知。如果我尝试将任何内容通过管道传输到合并的流中,那是行不通的。它只返回合并的流,并且永远不会继续。
如果我取消 promise 我的 PROCESS_SCRIPTS
函数并且不使用合并流(即只处理一个手动指定的文件夹),它工作正常,所以我不知道是什么继续。
这是我的完整任务:
module.exports = {
scripts(gulp, plugins, ran_tasks, on_error) {
// task-specific plugins
const ESLINT = require("gulp-eslint");
const WEBPACK = require("webpack-stream");
// process scripts
const PROCESS_SCRIPTS = (js_directory, destination_file_name = "modern.js", compare_file_name = "modern.js", source = [global.settings.paths.src + "/assets/scripts/*.js"]) => {
return new Promise((resolve, reject) => {
const WEBPACK_CONFIG = {
mode: "development",
};
// update webpack config for the current target destination and file name
WEBPACK_CONFIG.mode = plugins.argv.dist ? "production" : WEBPACK_CONFIG.mode;
WEBPACK_CONFIG.output = {
filename: destination_file_name
};
const TASK = gulp.src(source)
// prevent breaking on error
.pipe(plugins.plumber({errorHandler: on_error}))
// check if source is newer than destination
.pipe(plugins.newer(js_directory + "/" + compare_file_name))
// lint all scripts
.pipe(ESLINT())
// print lint errors
.pipe(ESLINT.format())
// run webpack
.pipe(WEBPACK(WEBPACK_CONFIG))
// generate a hash and add it to the file name
.pipe(plugins.hash({template: "<%= name %>.<%= hash %><%= ext %>"}))
// output scripts to compiled directory
.pipe(gulp.dest(js_directory))
// generate a hash manfiest
.pipe(plugins.hash.manifest(".hashmanifest-scripts", {
deleteOld: true,
sourceDir: js_directory
}))
// output hash manifest in root
.pipe(gulp.dest("."))
// reject after errors
.on("error", () => {
reject(TASK);
})
// return the task after completion
.on("end", () => {
resolve(TASK);
});
});
};
// scripts task, lints, concatenates, & compresses JS
return new Promise ((resolve) => {
// set JS directory
const JS_DIRECTORY = plugins.argv.dist ? global.settings.paths.dist + "/assets/scripts" : global.settings.paths.dev + "/assets/scripts";
// set the source directory
const SOURCE_DIRECTORY = global.settings.paths.src + "/assets/scripts";
// set up an empty merged stream
const MERGED_STREAMS = plugins.merge();
// get the script source folder list
const SCRIPT_FOLDERS = plugins.fs.readdirSync(SOURCE_DIRECTORY);
// get the script destination file list
const SCRIPT_FILES = plugins.fs.existsSync(JS_DIRECTORY) ? plugins.fs.readdirSync(JS_DIRECTORY) : false;
// process all the script folders
const PROCESS_SCRIPT_FOLDERS = () => {
return Promise.resolve().then(() => {
// shift to the next folder
const FOLDER_NAME = SCRIPT_FOLDERS.shift();
// find the existing destination script file name
const FILE_NAME = SCRIPT_FILES ? SCRIPT_FILES.find((name) => {
return name.match(new RegExp(FOLDER_NAME + ".[a-z0-9]{8}.js"));
}) : FOLDER_NAME + ".js";
// process all scripts, update the stream
return PROCESS_SCRIPTS(JS_DIRECTORY, FOLDER_NAME + ".js", FILE_NAME, SOURCE_DIRECTORY + "/" + FOLDER_NAME + "/**/*").then((processed) => {
MERGED_STREAMS.add(processed);
});
}).then(() => SCRIPT_FOLDERS.length > 0 ? PROCESS_SCRIPT_FOLDERS() : resolve());
};
PROCESS_SCRIPT_FOLDERS().then(() => {
// wrap up
return MERGED_STREAMS
// prevent breaking on error
.pipe(plugins.plumber({
errorHandler: on_error,
}))
// notify that task is complete, if not part of default or watch
.pipe(plugins.gulpif(gulp.seq.indexOf("scripts") > gulp.seq.indexOf("default"), plugins.notify({
title: "Success!",
message: "Scripts task complete!",
onLast: true,
})))
// push task to ran_tasks array
.on("data", () => {
if (ran_tasks.indexOf("scripts") < 0) {
ran_tasks.push("scripts");
}
})
// resolve the promise on end
.on("end", () => {
resolve();
});
});
});
}
};
在我的 GitHub 上也可见:https://github.com/JacobDB/new-site/blob/master/gulp-tasks/scripts.js
编辑:我已经尝试了一些东西,我会在这里详细说明。
console.log("hello world")
永远不会在 MERGED_STREAMS.on("data")
、MERGED_STREAMS.on("error")
,或 MERGED_STREAMS.on("end")
。const MERGED_STREAMS = plugins.merge();
移动到模块级变量(即紧接在 const WEBPACK = require("webpack-stream")
之后)不会改变结果。MERGED_STREAMS.add(gulp.src(source) ...)
而不是在 promise 完成后添加流不会改变结果,除非离开 .pipe(gulp.dist("."))
,它需要输出一个.hashmanifest
,并且始终将任务标记为已运行。webpack
、hash
或 eslint
的任何组合都不会产生任何影响。PROCESS_SCRIPTS
从返回 promise 更改为返回流,然后将每个文件夹作为单独的变量处理,然后手动合并它们似乎确实正确地触发了运行的任务,但是 webpack
只能运行一次,所以它只输出一个文件——critical.hash.js
。 注意:我没有在禁用 hash
的情况下测试此方法,如果始终输出 .hashmanifest
,这可能会导致它被标记为正确运行.lint
任务不是promise,这会导致控制台出现 unexpected end of stream
错误。编辑 2:根据@Louis 的建议更新了我的任务的修订版本。
最佳答案
上面的代码有很多问题。使代码难以跟踪和调试的一个主要问题是您在不需要的地方使用了 new Promise
。 通常,如果您有新的 Promise
,并且 promise 执行器中的逻辑将根据另一个 promise 的结果解决或拒绝,那么您不需要使用 新的 Promise
。
有时人们会有这样的代码:
function foo() {
const a = getValueSynchronously();
const b = getOtherValueSynchronously();
return doSomethingAsynchronous(a, b).then(x => x.someMethod());
}
假设 doSomethigAsynchronous
返回一个 promise 。上面的 foo
函数的问题在于,如果 getValueSynchronously
和 getOtherValueSynchronously
失败,那么 foo
将引发异常,但是如果 doSomethingAsynchronous
失败,那么它将拒绝 promise 。所以使用 foo
的代码必须处理同步异常和异步拒绝,如果它想处理所有可能的失败。有时人们觉得他们可以通过将所有失败都变成 promise 拒绝来解决问题:
function foo() {
return new Promise((resolve, reject) => {
const a = getValueSynchronously();
const b = getOtherValueSynchronously();
doSomethingAsynchronous(a, b).then(x => x.someMethod()).then(resolve, reject);
});
}
在上面的代码中,如果 getValueSynchronously
或 getOtherValueSynchronously
失败,那就是 promise 拒绝。但是上面代码的问题是很容易出错。您可以忘记在需要的地方调用 reject
。 (事实上 ,您的代码中确实有此错误。您有嵌套的 promise ,其拒绝不会向上传播。它们只是丢失,这意味着如果发生错误你的代码会在你不知道原因的情况下停止。)或者你可能想在嵌套函数中调用 `resolve 方法,这使得逻辑难以遵循。
你也可以这样做:
function foo() {
return Promise.resolve().then(() => {
const a = getValueSynchronously();
const b = getOtherValueSynchronously();
return doSomethingAsynchronous(a, b);
}).then(x => x.someMethod());
}
您可以使用 Promise.resolve()
进入应许的世界(嗯……“应许之地?”)。在上面的代码中,您不必记住调用 reject
。如果 .then
回调中的代码出于任何原因失败,您将得到一个被拒绝的 promise 。
我还注意到,在许多地方,您从传递给 new Promise
的执行程序函数中返回了一个值。如果您不在那里使用 return
,您的代码将表现得完全相同。为了说明这一点,这段代码:
function foo() {
return new Promise((resolve, reject) => {
return doSomethingAsynchronous().then(resolve, reject);
});
}
与此代码的行为完全相同:
function foo() {
return new Promise((resolve, reject) => {
doSomethingAsynchronous().then(resolve, reject);
});
}
从执行器返回的值被忽略。故事结局。如果您认为从执行程序返回的值正在做某事,那是不正确的。
关于javascript - 合并的 gulp 任务从不触发 `end` 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52613825/
Task.WaitAll 方法等待所有任务,Task.WaitAny 方法等待一个任务。如何等待任意N个任务? 用例:下载搜索结果页面,每个结果都需要一个单独的任务来下载和处理。如果我使用 WaitA
我正在查看一些像这样的遗留 C# 代码: await Task.Run(() => { _logger.LogException(LogLevel.Error, mes
如何在 Linux 中运行 cron 任务? 关注此Q&A ,我有这个 cron 任务要运行 - 只是将一些信息写入 txt 文件, // /var/www/cron.php $myfile = fo
原谅我的新手问题,但我想按顺序执行三个任务并在剧本中使用两个角色: 任务 角色 任务 角色 任务 这是我到目前为止(任务,角色,任务): --- - name: Task Role Task ho
我有一个依赖于 installDist 的自定义任务 - 不仅用于执行,还依赖于 installDist 输出: project.task('run', type: JavaExec, depends
从使用 Wix 创建的 MSI 运行卸载时,我需要在尝试删除任何文件之前强行终止在后台运行的进程。主要应用程序由一个托盘图标组成,它反射(reflect)了 bg 进程监控本地 Windows 服务的
我想编写 Ant 任务来自动执行启动服务器的任务,然后使用我的应用程序的 URL 打开 Internet Explorer。 显然我必须执行 startServer先任务,然后 startApplic
使用 ASP.NET 4.5,我正在尝试使用新的 async/await 玩具。我有一个 IDataReader 实现类,它包装了一个特定于供应商的阅读器(如 SqlDatareader)。我有一个简
使用命令 gradle tasks可以得到一份所有可用任务的报告。有什么方法可以向此命令添加参数并按任务组过滤任务。 我想发出类似 gradle tasks group:Demo 的命令筛选所有任务并
除了sshexec,还有什么办法吗?任务要做到这一点?我知道您可以使用 scp 复制文件任务。但是,我需要执行其他操作,例如检查是否存在某些文件夹,然后将其删除。我想使用类似 condition 的东
假设我有字符串 - "D:\ApEx_Schema\Functions\new.sql@@\main\ONEVIEW_Integration\3" 我需要将以下内容提取到 diff 变量中 - 文档名
我需要编写一个 ant 任务来确定某个文件是否是只读的,如果是,则失败。我想避免使用自定义选择器来为我们的构建系统的性质做这件事。任何人都有任何想法如何去做?我正在使用 ant 1.8 + ant-c
这是一个相当普遍的计算机科学问题,并不特定于任何操作系统或框架。 因此,我对与在线程池上切换任务相关的开销感到有些困惑。在许多情况下,给每个作业分配自己的特定线程是没有意义的(我们不想创建太多硬件线程
我正在使用以下 Ansible playbook 一次性关闭远程 Ubuntu 主机列表: - hosts: my_hosts become: yes remote_user: my_user
如何更改 Ant 中的当前工作目录? Ant documentation没有 任务,在我看来,最好的做法是不要更改当前工作目录。 但让我们假设我们仍然想这样做——你会如何做到这一点?谢谢! 最佳答案
是否可以运行 cronjob每三天一次?或者也许每月 10 次。 最佳答案 每三天运行一次 - 或更短时间在月底运行一次。 (如果上个月有 31 天,它将连续运行 2 天。) 0 0 */3 * *
如何在 Gradle 任务中执行托管在存储库中的工具? 在我的具体情况下,我正在使用 Gradle 构建一个 Android 应用程序。我添加了一项任务,将一些 protobuf 数据从文本编码为二进
我的项目有下一个结构: Root |- A |- C (depends on A) \- B (depends on A) 对于所有子项目,我们使用自己的插件生成资源:https://githu
我设置了一个具有4个节点的Hadoop群集,其中一个充当HDFS的NameNode以及Yarn主节点。该节点也是最强大的。 现在,我分发了2个文本文件,一个在node01(名称节点)上,一个在node
在 TFS 2010 中为多个用户存储任务的最佳方式是什么?我只能为一项任务分配一个。 (例如:当我计划向所有开发人员演示时) (这是一个 Scrum Msf 敏捷项目,其中任务是用户故事的一部分)
我是一名优秀的程序员,十分优秀!