cli
是libsquoosh的命令行工具盹靴,可以直接在命令行中直接運(yùn)行掀宋。
Cli的核心流程分析
cli使用commander
包來(lái)實(shí)現(xiàn)命令行界面钉鸯,核心函數(shù)是processFiles
,執(zhí)行的關(guān)鍵流程是
- 讀文件
const buffer = await fsp.readFile(file);
- 解碼得到image 的原始data鹅巍,也就是未壓縮的數(shù)據(jù):
const image = imagePool.ingestImage(buffer);
await image.decoded;
ingestImage
會(huì)創(chuàng)建一個(gè)新的Image
對(duì)象音同,該對(duì)象的構(gòu)造函數(shù)會(huì)通過(guò)WorkerPool
的dispatchJob
post 一個(gè)decode
的message到WorkerPool
的jobQueue
中词爬,WorkerPool
則pick 一個(gè)worker
,并用這個(gè)worker
來(lái)做實(shí)際的解碼权均;dispatchJob
是一個(gè)異步操作顿膨, 內(nèi)部會(huì)創(chuàng)建一個(gè)新的Promise
對(duì)象,該對(duì)象會(huì)在圖像解碼的完成的時(shí)候叽赊,把解碼得到的buffer作為返回值返回恋沃,也即該對(duì)象的實(shí)際結(jié)果。
await image.decoded
就是等待解碼完成必指。
- 解析
preprocessors
的選項(xiàng):
const preprocessOptions = {};
for (const preprocessorName of Object.keys(preprocessors)) {
if (!program.opts()[preprocessorName]) {
continue;
}
preprocessOptions[preprocessorName] = JSON5.parse(
program.opts()[preprocessorName],
);
}
這部分主要是檢查是否有preprocessors
的相關(guān)參數(shù)囊咏,有的話就構(gòu)造一個(gè)option.
- 調(diào)用
preprocess
for (const image of decodedFiles) {
image.preprocess(preprocessOptions);
}
await Promise.all(decodedFiles.map((image) => image.decoded));
注意image.preprocess
是一個(gè)async函數(shù),但他本身的結(jié)果或者返回值本身并不重要塔橡。它內(nèi)部調(diào)用this.workerPool.dispatchJob
讓worker_pool來(lái)做實(shí)際的preprocess
操作梅割,并把對(duì)應(yīng)的Promise
賦值給image.decoded
。因此在調(diào)用preprocess
之后谱邪,還需要再調(diào)用await Promise.all
來(lái)等待所有image.decoded
的完成炮捧。
- 調(diào)用實(shí)際的encoder
const job = image.encode(encodeOptions).then(async () => {
jobsFinished++;
const outputPath = path.join(
program.opts().outputDir,
path.basename(originalFile, path.extname(originalFile)) +
program.opts().suffix,
);
for (const output of Object.values(image.encodedWith)) {
const outputFile = `${outputPath}.${(await output).extension}`;
await fsp.writeFile(outputFile, (await output).binary);
results
.get(image)
.outputs.push(Object.assign(await output, { outputFile }));
}
progress.setProgress(jobsFinished, jobsStarted);
});
jobs.push(job);
注意job
是一個(gè)Promise
對(duì)象庶诡,它是由then()
里面的異步函數(shù)創(chuàng)建惦银,這個(gè)異步對(duì)象在image.encode
完成異步操作后才會(huì)被觸發(fā)。因此這里不需要顯式等待encode對(duì)象的完成末誓,取而代之則是等待jobs
的完成扯俱。所以最后還需要等待所有job的完成。
await Promise.all(jobs);
- 代碼清理
await imagePool.close();
用來(lái)關(guān)掉imagePool
.
相關(guān)語(yǔ)法解析
Object
Object.keys()
返回一個(gè)對(duì)象自己的可枚舉的屬性名字喇澡;
// Simple array
const arr = ["a", "b", "c"];
console.log(Object.keys(arr)); // ['0', '1', '2']
// Array-like object
const obj = { 0: "a", 1: "b", 2: "c" };
console.log(Object.keys(obj)); // ['0', '1', '2']
// Array-like object with random key ordering
const anObj = { 100: "a", 2: "b", 7: "c" };
console.log(Object.keys(anObj)); // ['2', '7', '100']
Object.values()
: 返回對(duì)象可枚舉的屬性的值迅栅;
Object.entries()
:返回對(duì)象的屬性的名字和值;
Object.assign()
: 把源對(duì)象的屬性拷貝到目標(biāo)對(duì)象中晴玖,例如:
const preprocessorOptions = Object.assign(
{},
preprocessors[preprocessorName].defaultOptions,
options,
);
相當(dāng)于把defaultOptions
和options
拷貝到目標(biāo)對(duì)象preprocessorOptions
中读存;
map
map是對(duì)數(shù)組中所有元素都執(zhí)行相同操作/函數(shù)为流,并生成一個(gè)新的數(shù)組;例如
const arr = [1, 2, 3];
const syncRes = arr.map((i) => {
return i + 1;
});
console.log(syncRes);
// 2,3,4
map的異步版本是指操作的函數(shù)是異步的让簿,返回的對(duì)象也是Promise敬察,再使用Promise.all來(lái)等待所有的結(jié)果都處理完;例如
file_contents = await Promise.all(files.map(async (file) => {
const buffer = await fsp.readFile(file);
return buffer;
}));
這里面分成兩步尔当,file.map返回的對(duì)象是Promise對(duì)象莲祸,而Promise.all返回的則是真正的內(nèi)容;
異步操作await/promise
await
await
用于等待一個(gè)Promise
對(duì)象實(shí)際執(zhí)行完成椭迎,并返回真實(shí)操作的結(jié)果锐帜。例如
const buffer = await fsp.readFile(file)
等待文件操作的實(shí)際完成,并把結(jié)果保存到buffer中畜号。
Promise.all
await Promise.all
用于同時(shí)等待多個(gè)Promise對(duì)象缴阎。
files.map(async (file) => {
console.log("Open file " + file);
const buffer = await fsp.readFile(file);
const image = imagePool.ingestImage(buffer);
await image.decoded;
results.set(image, {
file,
size: (await image.decoded).size,
outputs: [],
});
progress.setProgress(++decoded, files.length);
return image;
}
這一段代碼則是把file數(shù)組轉(zhuǎn)換成Promise
對(duì)象的數(shù)組,這個(gè)Promise對(duì)象實(shí)際返回結(jié)果是image
類(lèi)型简软。這是一種通用的模式async map:
Promise.all(arr.map(async (...) => ...))).