Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

异步处理实战 #44

Open
shenfeng1945 opened this issue Jul 2, 2019 · 0 comments
Open

异步处理实战 #44

shenfeng1945 opened this issue Jul 2, 2019 · 0 comments

Comments

@shenfeng1945
Copy link
Owner

shenfeng1945 commented Jul 2, 2019

异步处理实战

查找指定目录下的最大文件为例,感受下从

回调函数 > Promise > Generator > Async

异步处理方式的改变

思路分析

  1. fs.readdir读取某个目录下所有文件列表
  2. 遍历文件列表,fs.stat读取文件信息,并保存在数组中
  3. 过滤掉非文件类型的,利用sort对文件的size进行递减排序,返回最大的文件名

回调函数

const fs = require('fs');
const path = require('path');

function findLargest(dir, cb) {
    let statArray = [];
    let errorStat = false;
    fs.readdir(dir, (dirErr, filenames) => {
        if (dirErr) { cb(dirErr); return }
        filenames.forEach((file, index) => {
            fs.stat(path.join(dir, file), (statErr, statData) => {
                if (errorStat) return;
                if (statErr) {
                    cb(statErr);
                    errorStat = true;
                    return
                }
                statArray.push({ file, stat: statData })
                if (index === filenames.length - 1) {
                    let result = statArray.filter(statObj => statObj.stat.isFile()).sort((a, b) => b.stat.size - a.stat.size)
                    cb(false, result[0].file)
                }
            })
        })
    })
}

findLargest('./images', function (err, file) {
    if (err) { console.error(res); return }
    console.log(`largest file is ${file}`)
})

代码中回调嵌套着回调,代码冗余。

Promise

const fs = require('fs');
const path = require('path');

const readdir = dir => {
    return new Promise((resolve, reject) => {
        fs.readdir(dir, (dirErr, filenames) => {
            if (dirErr) reject(dirErr);
            resolve(filenames)
        })
    })
}

const getStat = (dir, filename) => {
    return new Promise((resolve, reject) => {
        fs.stat(path.join(dir, filename), (statErr, stat) => {
            if (statErr) reject(statErr);
            resolve({file: filename, stat});
        })
    })
}

function findLargest(dir) {
    return readdir(dir).then(filenames => {
        let promises = filenames.map(filename => getStat(dir, filename));
        return Promise.all(promises).then(res => {
          let result = res.filter(statObj => statObj.stat.isFile()).sort((a,b) => b.stat.size - a.stat.size);
          return result[0].file
        })
    })
}


findLargest('./images').then(file => {
    console.log(`largest file is ${file}`)
}).catch(err => console.error(err))

代码结构比回调函数的好了很多,readdirgetStat可以抽离出来,逻辑也清晰了,但then仍存在嵌套。

Generator

const fs = require('fs');
const path = require('path');
const co = require('./lib/co.js');

function* findLargest (dir){
  const filenames = yield readdir(dir);
  const statArray = yield filenames.map(filename => getStat(dir, filename));
  const result = statArray.filter(statObj => statObj.stat.isFile()).sort((a,b) => b.stat.size - a.stat.size);
  return result[0].file
}

co(findLargest, './images').then(file => {
    console.log(`largest file is ${file}`)
}).catch(err => console.error(err))

// 不使用co模板
const data = findLargest('./images');
data.next().value.then(filenames => {
    const statArray = data.next(filenames);
    return Promise.all(statArray.value)
}).then(res => {
    console.log(`largest file is ${data.next(res).value}`)
});

配合co函数库效果更好,不使用co的话,执行Generator函数,得到遍历器对象,调用next方法分别执行异步任务三个阶段。

Async

async function findLargest(dir){
  const filenames = await readdir(dir);
  const promises = filenames.map(filename => getStat(dir, filename));
  const statArray = await Promise.all(promises);
  const result = statArray.filter(statObj => statObj.stat.isFile()).sort((a,b) => b.stat.size - a.stat.size);
  return result[0].file
}

findLargest('./images').then(file => {
    console.log(`largest file is ${file}`)
}).catch(err => console.error(err));

用了async无需再手动执行next方法,基于了GeneratorPromise的一层封装。

参考文章

  1. ES6 系列之异步处理实战
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant