这个问题我可能与角度概念没有任何关系。但是我在有角度的背景下遇到了它。我单击角度模板中的按钮,它会触发onSubmit函数。
scanFiles是一个长时间运行的函数,它返回一个Promise。我希望console.log(“ test1”)可以在长时间运行的函数开始之前打印出来。但是那不会发生。仅在长时间运行功能完成后才打印。为什么会这样?
onSubmit(){
this.scanFiles(this.foldersPath).then((filesPath)=>{
//after scan finish
})
.catch((err)=>console.log(err))
console.log("test1")
}
2019年10月7日进一步更新)
如下所示,我的scanFiles函数返回一个promise。因此,无论我的诺言工作做什么,从理论上讲,我认为在浏览器开始执行诺言工作之前,应先打印出“ test1”。
scanFiles(foldersPath: any):Promise<string[]> {
return new Promise(
(resolveFn, rejectFn)=>{
try{
const scanResult:string[]= foldersPath.reduce(
(prevFolderPath:string[], currFolderPath:string)=> {
let files:string[] = this.fileService.getContentInDirectory (currFolderPath, this.filter.bind(this), this.getProcessDirectoryContentFn(), this.subfolderDepthInput)
prevFolderPath.push(...files)
return prevFolderPath
},new Array<string>())
console.log(scanResult)
resolveFn(scanResult)
}
catch(e){
console.log(e)
rejectFn(e)
}
}
)
``
于2019年10月8日更新 geContentInDirectory内部有一个readdirSync()函数
getContentInDirectory(dir:string, filterContentFn?:(fullPath:string)=>boolean, processContentFn?:(fullPath:any)=>string, maxSubFolderDepth?:number ): string[]{
let paths:string[]=[];
//const dir_NOT_A_DIRECTORY =
if(!dir || !fs.lstatSync(dir).isDirectory())
throw new Error("First Parameter must be a directory")
fs.readdirSync(dir).forEach(entityName=>{
let fullPath:string = path.join(dir, entityName)
let isFile = fs.lstatSync(fullPath).isFile()
if(maxSubFolderDepth==undefined || maxSubFolderDepth >= 0){
if(isFile){
if(filterContentFn) {
if(filterContentFn(fullPath)){
let content = processContentFn? processContentFn(fullPath): fullPath
paths.push(content)
}
}
}
else {
const depth = maxSubFolderDepth==undefined ? undefined: maxSubFolderDepth-1
paths.push(...this.getContentInDirectory(fullPath, filterContentFn, processContentFn, depth))
}
}
})
return paths;
}
}
于2019年10月8日更新
我通过重写代码来做一个实验: 结果是依次输出“ test0”,“ test2”,“ test1”。
结论:创建诺言对象时,其在诺言对象中定义的长期运行的作业将被触发并立即执行。 我的scanFiles完成工作后,将打印“ test0”。
然后在promise的then函数中注册(注册,但尚未执行)回调。然后打印test2”。线程然后返回其事件循环,发现它仍然需要处理回调函数,从而导致“ test1”被打印
let p= this.scanFiles(this.foldersPath)
console.log("test0")
p.then((filesPath)=>{
console.log("test1")
})
.catch((err)=>console.log(err))
console.log("test2")
感谢 Tomalak 用户的解决方案和解释,这使我对上面的内容有所了解。
答案到我的问题:我的Promise对象内部包含同步任务。难怪只有在promise对象中的任务完成后,我的“ test1”(指的是我的最高代码)才被打印出来。
答案 0 :(得分:1)
据我对您当前代码的理解,这是getContentInDirectory
的完全异步,应许返回的版本。为了进行测试,我发现TypeScript太吵了,将其删除,然后根据需要添加回去。
function getContentInDirectory(dir, filterContentFn, processContentFn, maxSubFolderDepth) {
return new Promise((resolve, reject) => {
let result = [], pending = 0;
function worker(currPath, depth) {
pending++;
fs.lstat(currPath, (err, stat) => {
pending--;
if (err) return reject(err);
if (stat.isDirectory()) {
if (depth >= 0) {
pending++;
fs.readdir(currPath, (err, children) => {
pending--;
if (err) return reject(err);
children.forEach(name => worker(path.join(currPath, name), depth - 1));
});
}
} else if (!filterContentFn || filterContentFn(currPath)) {
result.push(processContentFn ? processContentFn(currPath) : currPath);
}
if (!pending) resolve(result);
});
}
worker(dir, maxSubFolderDepth >= 0 ? maxSubFolderDepth : Infinity);
});
}
有多种方法可以实现此目的,包括使用fs Promises API,它从节点版本10开始可用,但至今仍标记为“实验性”。上面没有做任何假设,并且适用于任何节点版本。
现在您可以本着以下精神在scanFiles
中使用它:
function scanFiles(foldersPath) {
let pendingPaths = foldersPath.map(currFolderPath => {
return getContentInDirectory(currFolderPath, filterFunc, processFunc, depth);
});
return Promise.all(pendingPaths).then(results => {
return Array.prototype.concat.apply([], results); // flatten
});
}
最后在您的事件处理程序中:
onSubmit(){
this.scanFiles(this.foldersPath).then(filesPath => {
// after scan finish
console.log("this prints last");
})
.catch(err => console.log(err));
console.log("this prints first");
}
这里要注意的是,如果您想使自己使用的功能也要异步,那么从一开始就需要进行实际工作的功能是异步的。从节点fs
功能的“同步”版本切换到常规的异步对应版本是至关重要的步骤。
当然,此更改意味着程序中每个getContentInDirectory
的使用者都必须更改为异步代码。
答案 1 :(得分:0)
您可以将多个然后链接在一起:
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
}).then(function(result) { // (***)
alert(result); // 2
return result * 2;
}).then(function(result) {
alert(result); // 4
return result * 2;
});
想法是将结果通过.then处理程序链传递。
这里的流程是:
最初的承诺在1秒内解决(), 然后,.then处理程序称为()。 它返回的值将传递到下一个.then处理程序( ) …等等。
或者您可以在最终执行后执行一些操作,最后将其写入:
let isLoading = true;
fetch(myRequest).then(function(response) {
var contentType = response.headers.get("content-type");
if(contentType && contentType.includes("application/json")) {
return response.json();
}
throw new TypeError("Oops, we haven't got JSON!");
})
.then(function(json) { /* process your JSON further */ })
.catch(function(error) { console.error(error); /* this line can also throw, e.g. when console = {} */ })
.finally(function() { isLoading = false; });