Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Node.js在递归循环中返回承诺_Javascript_Node.js_Recursion_Promise_Fs - Fatal编程技术网

Javascript Node.js在递归循环中返回承诺

Javascript Node.js在递归循环中返回承诺,javascript,node.js,recursion,promise,fs,Javascript,Node.js,Recursion,Promise,Fs,我很难让循环以正确的顺序返回嵌套的承诺。 我试图递归地循环遍历一个包含子目录的目录,以获取文件并将其复制到一个新目录。此功能发生在承诺链中,因为复制文件后,其他进程需要按顺序完成 下面的代码可以工作,但当I console.log退出之后的字符串时,

我很难让循环以正确的顺序返回嵌套的承诺。 我试图递归地循环遍历一个包含子目录的目录,以获取文件并将其复制到一个新目录。此功能发生在承诺链中,因为复制文件后,其他进程需要按顺序完成

下面的代码可以工作,但当I console.log退出
之后的字符串时,
代码是:

    let newDirectory = /// helper function that returns promise of mkdirSync(exampleDir)
    newDirectory.then(function(result){
        getAllFiles('/TestDir').then((result) => {
            console.log(result);
        });
        console.log('this should fire after the "result" from above');
        //// rest of promises in promise chain
    });
        
我调用的递归函数“getAllFiles”遍历“TestDir”及其子文件夹,并将文件复制到“ExampleDir”

复制文件的助手在复制文件后返回承诺

exports.copyFile = function(file, destDir){
  return new Promise(function ( resolve, reject ){
        fs.copyFile(file, destDir, (err) => {
          if(err) reject( err );
          else resolve('Successfully copied');
        });
   });
}
这实际上似乎是可行的,但我担心它无法处理大量数据,因为

console.log('this should fire after the "result" from above');
在其他日志之前触发。控制台看起来像:

this should fire after the "result" from above
done with Promises        /// how ever many files are copied
[ 'Successfully copied']   //// with a length of however many files are copied)
done with Promises        //// this is fired once

这是一个预期的日志,还是所有的承诺都应该在“'this should fire after the“result”from over”行被记录之前解决并记录?

如果您想在
承诺之后控制台日志,您必须在
中执行。然后()

Promise.all(promises).then(函数(结果){
决心(结果);
log('done with promissions');
})
。然后(()=>console.log(“这应该在上面的“结果”之后触发”))
.catch((错误)=>拒绝(错误));

这是因为
Promise
s是非阻塞的,它之后的任何操作都不会等到它完成后再执行。

fs/promises和fs.Dirent

let newDirectory = /// helper function that returns promise of mkdirSync(exampleDir)
newDirectory.then(function(result){
    getAllFiles('/TestDir').then((result) => {
        console.log(result);
    });
    console.log('this should fire after the "result" from above');
    //// rest of promises in promise chain
});
这是一个高效、无阻塞的
ls
程序,使用节点的快速对象和模块。这种方法允许您跳过每个路径上浪费的
fs.exist
fs.stat
调用

使用
async
await
,我们可以避免过多地考虑如何具体实现承诺-

// main.js
import { readdir } from "fs/promises"
import { join } from "path"

async function* ls (path = ".")
{ yield path
  for (const dirent of await readdir(path, { withFileTypes: true }))
    if (dirent.isDirectory())
      yield* ls(join(path, dirent.name))
    else
      yield join(path, dirent.name)
}

async function* empty () {}

async function toArray (iter = empty())
{ let r = []
  for await (const x of iter)
    r.push(x)
  return r
}

toArray(ls(".")).then(console.log, console.error)
让我们获取一些示例文件,这样我们就可以看到
ls
正在工作-

$warn add immutable#(只是一些示例包)
$node main.js
[
'.',
'main.js',
“节点_模块”,
“节点\单元/纱线完整性”,
“节点_模块/不可变”,
“节点\模块/不可变/许可证”,
“node_modules/immutable/README.md”,
“节点\模块/不可变/可控”,
“节点\模块/不可变/控制/游标”,
'node_modules/immutable/contrib/cursor/README.md',
'节点\模块/不可变/contrib/cursor/\测试\',
'节点\模块/immutable/contrib/cursor/\测试\测试\ cursor.ts.skip',
“node_modules/immutable/contrib/cursor/index.d.ts”,
'node_modules/immutable/contrib/cursor/index.js',
“节点\模块/不可变/dist”,
'node_modules/immutable/dist/immutable nonambient.d.ts',
'node_modules/immutable/dist/immutable.d.ts',
'node_modules/immutable/dist/immutable.es.js',
'node_modules/immutable/dist/immutable.js',
'node_modules/immutable/dist/immutable.js.flow',
'node_modules/immutable/dist/immutable.min.js',
“node_modules/immutable/package.json”,
'package.json',
“纱线,锁”
]
有关递归列出目录的
dir
程序、查找文件的
search
程序,以及更多信息,请参见本节

这是一个预期的日志,还是应该在“这应该在上面的“结果”之后触发”行被记录之前解决并记录所有承诺

是的,这是意料之中的。 当
承诺
并非用于同步时,您编写的代码就好像是同步的。 下面的代码片段中实际发生的是在
newDirectory
Promise解析之后,
getAllFiles
console.log('这应该在上面的“结果”之后触发)')功能将立即执行。也就是说,console.log在执行之前不会等待
getAllFiles
解析

let newDirectory = /// helper function that returns promise of mkdirSync(exampleDir)
newDirectory.then(function(result){
    getAllFiles('/TestDir').then((result) => {
        console.log(result);
    });
    console.log('this should fire after the "result" from above');
    //// rest of promises in promise chain
});
因此,如果您想更改console.log的顺序,以确保它在
getAllFiles
Promise解析后执行,您可以按如下方式重写

newDirectory.then(function(result){
    getAllFiles('/TestDir').then((result) => {
        console.log(result);
        // or you could add it here
    }).then(() => { 
      console.log('this should fire after the "result" from above');
    });
});
您还应该注意到,我所说的是当承诺解决时,而不是当函数完成执行时。有一个非常重要的区别。 如果我们再次以上面的示例为例,并说我们希望在复制完所有文件后执行其他操作

newDirectory.then(function(result){
    getAllFiles('/TestDir').then((result) => {
       ...
    });
}).then(() => {
    console.log('doing some other task');
});
在上面的示例中,将发生的是解析
newDirectory
承诺,然后调用
getAllFiles
,并且
getAllFiles
完成执行之前,将记录最终的console.log。这是承诺的一个重要原则,如果您希望它们同步运行,您需要链接承诺,即您需要通过所有链接的then函数返回承诺。因此,要解决上述问题,我们需要返回通过
getAllFiles
函数解决的承诺,如下所示

newDirectory.then(function(result){
    return getAllFiles('/TestDir').then((result) => {
       ...
    });
}).then(() => {
    console.log('doing some other task');
});

基于我对node的理解。第二个日志的第一位代码将按顺序出现。这意味着您首先得到承诺,然后->触发承诺链->日志->最终解析getAllFiles链中的所有承诺。您能在代码段中使用更清晰的缩进吗?这将使您的问题更容易回答。感谢您的编辑,但在
getAllFiles
中,您的第三个代码段中的括号似乎仍有一些不匹配的地方,请避免!(假设代码实际上是嵌套工作的,不要过早返回并将
承诺保留。所有
位都作为死代码)