Javascript for循环中异步函数的顺序
考虑以下for循环Javascript for循环中异步函数的顺序,javascript,asynchronous,Javascript,Asynchronous,考虑以下for循环 import * as fs from 'fs' function listAllJs() { let files = [ 'abc.js', 'bcd.js', 'e', 'main.js', 'maincopy.ts', 'mainfixedbug.ts', 'package-lock.json', 'package.json' ] for (let i = 0; i<files.length; i++) { let file = file
import * as fs from 'fs'
function listAllJs() {
let files = [ 'abc.js', 'bcd.js', 'e', 'main.js', 'maincopy.ts', 'mainfixedbug.ts', 'package-lock.json', 'package.json' ]
for (let i = 0; i<files.length; i++) {
let file = files[i]
fs.stat(file, (err, stat) => {
console.log(i, file)
});
}
}
listAllJs()
或
或其他可能的组合,如1 3 2 4 6 7 5
索引不是按升序排列的,终端将打印出不同的顺序。但是当我在异步函数之前添加console.log(i)时
function listAllJs() {
let files = [ 'abc.js', 'bcd.js', 'e', 'main.js', 'maincopy.ts', 'mainfixedbug.ts', 'package-lock.json', 'package.json' ]
for (let i = 0; i<files.length; i++) {
let file = files[i]
console.log(i)
fs.stat(file, (err, stat) => {
console.log(i, file)
});
}
}
我知道这类问题很没用,但我正在学习异步函数,我真的想知道它背后的原因。有什么解释吗?“stat”正在后台运行,您的程序将在不等待完成的情况下继续运行。因此,它的多个实例同时运行,这使得哪个实例将首先打印输出变得不可预测。您的“console.log(i)”可能需要足够长的时间来确定哪个先完成。“stat”在后台运行,您的程序将继续运行,而不等待它完成。因此,它的多个实例同时运行,这使得哪个实例将首先打印输出变得不可预测。您的“console.log(i)”可能需要足够长的时间来确定哪个先完成。无法保证运行和触发回调函数所需的时间 当您的循环只调用它时,各种调用非常接近,并且
fs.stat
运行的时间段重叠。有时一个开始晚的人会结束得更快
当您添加console.log
语句时,会使每个循环的时间稍微延长一点
在您的特定测试用例中,在您的计算机上,当您的计算机处于您正在品尝的负载下时,会发生这种情况,使完成循环电路所需的时间略长于获取数据所需的时间fs.stat
由于对fs.stat
的调用间隔更大,因此它们恰好按顺序完成
你不能依赖这种行为
如果您想让他们按顺序返回,则:
listAllJs
等待
承诺并收集其返回值并记录该值无法保证运行并触发回调函数需要多长时间 当您的循环只调用它时,各种调用非常接近,并且
fs.stat
运行的时间段重叠。有时一个开始晚的人会结束得更快
当您添加console.log
语句时,会使每个循环的时间稍微延长一点
在您的特定测试用例中,在您的计算机上,当您的计算机处于您正在品尝的负载下时,会发生这种情况,使完成循环电路所需的时间略长于获取数据所需的时间fs.stat
由于对fs.stat
的调用间隔更大,因此它们恰好按顺序完成
你不能依赖这种行为
如果您想让他们按顺序返回,则:
listAllJs
等待
承诺并收集其返回值并记录该值fs/promises和fs.Dirent 这是一个高效、无阻塞的
ls
程序,使用节点的快速对象和模块。这种方法允许您跳过每个路径上浪费的fs.exist
或fs.stat
调用-
// 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',
“纱线,锁”
]
我们只想过滤文件-
从“路径”导入{extname}
异步函数*过滤器(iter=empty(),test=x=>x)
{等待(国际热核实验堆常数x)
if(布尔(测试(x)))
产量x
}
const lsJs=(path=“.”)=>
过滤器//
提取
? 过滤器(ls(路径),p=>extname(p)==ext)
:ls(路径)
toArray(lsExt(“.”,“.json”)。然后(console.log,console.error)
// => ...
[
“node_modules/immutable/package.json”,
'package.json'
]
调试承担太多责任的大函数是很困难的。解决这个问题使我们的程序更容易编写,我们的函数也具有高度的可重用性。下一步是在模块中定义我们的一组功能。有关利用异步生成器的补充说明和其他方法,请参阅。fs/promises和fs.Dirent
这是一个高效、无阻塞的ls
程序,使用节点的快速对象和模块。这种方法允许您跳过浪费的fs.exist
或fs.stat
调用
function listAllJs() {
let files = [ 'abc.js', 'bcd.js', 'e', 'main.js', 'maincopy.ts', 'mainfixedbug.ts', 'package-lock.json', 'package.json' ]
for (let i = 0; i<files.length; i++) {
let file = files[i]
console.log(i)
fs.stat(file, (err, stat) => {
console.log(i, file)
});
}
}
0
1
2
3
4
5
6
7
0 abc.js
1 bcd.js
2 e
3 main.js
4 maincopy.ts
5 mainfixedbug.ts
6 package-lock.json
7 package.json
function getStat(file) {
return new Promise( (res, rej) => {
fs.stat(file, (err, stat) => {
res(file);
});
};
}
function listAllJs() {
let files = [ 'abc.js', 'bcd.js', 'e', 'main.js', 'maincopy.ts', 'mainfixedbug.ts', 'package-lock.json', 'package.json' ]
for (let i = 0; i<files.length; i++) {
let file = files[i];
const stat = await getStat(file);
console.log(i, stat)
}
}
function listAllJs() {
let files = [ 'abc.js', 'bcd.js', 'e', 'main.js', 'maincopy.ts', 'mainfixedbug.ts', 'package-lock.json', 'package.json' ];
const promises = [[];
for (let i = 0; i<files.length; i++) {
let file = files[i];
const stat = getStat(file);
promises.push(stat);
}
const stats = await Promise.all(promises);
stats.forEach( (stat, index) {
console.log(index, stat)
});
}
// 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)