• ES6 系列之异步处理实战


    前言

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

    回调函数 -> Promise -> Generator -> Async

    异步处理方式的改变。

    API 介绍

    为了实现这个功能,我们需要用到几个 Nodejs 的 API,所以我们来简单介绍一下。

    fs.readdir

    readdir 方法用于读取目录,返回一个包含文件和目录的数组。

    fs.stat

    stat 方法的参数是一个文件或目录,它产生一个对象,该对象包含了该文件或目录的具体信息。此外,该对象还有一个 isFile() 方法可以判断正在处理的到底是一个文件,还是一个目录。

    思路分析

    我们基本的实现思路就是:

    1. fs.readdir 获取指定目录的内容信息
    2. 循环遍历内容信息,使用 fs.stat 获取该文件或者目录的具体信息
    3. 将具体信息储存起来
    4. 当全部储存起来后,筛选其中的是文件的信息
    5. 遍历比较,找出最大文件
    6. 获取并返回最大文件

    然后我们直接上代码吧。

    回调函数

    
    var fs = require('fs');
    var path = require('path');
    
    function findLargest(dir, cb) {
        // 读取目录下的所有文件
        fs.readdir(dir, function(er, files) {
            if (er) return cb(er);
    
            var counter = files.length;
            var errored = false;
            var stats = [];
    
            files.forEach(function(file, index) {
                // 读取文件信息
                fs.stat(path.join(dir, file), function(er, stat) {
    
                    if (errored) return;
    
                    if (er) {
                        errored = true;
                        return cb(er);
                    }
    
                    stats[index] = stat;
    
                    // 事先算好有多少个文件,读完 1 个文件信息,计数减 1,当为 0 时,说明读取完毕,此时执行最终的比较操作
                    if (--counter == 0) {
    
                        var largest = stats
                            .filter(function(stat) { return stat.isFile() })
                            .reduce(function(prev, next) {
                                if (prev.size > next.size) return prev
                                return next
                            })
    
                        cb(null, files[stats.indexOf(largest)])
                    }
                })
            })
        })
    }
    

    使用方式为:

    
    // 查找当前目录最大的文件
    findLargest('./', function(er, filename) {
        if (er) return console.error(er)
        console.log('largest file was:', filename)
    });
    

    Promise

    
    var fs = require('fs');
    var path = require('path');
    
    var readDir = function(dir) {
        return new Promise(function(resolve, reject) {
            fs.readdir(dir, function(err, files) {
                if (err) reject(err);
                resolve(files)
            })
        })
    }
    
    var stat = function(path) {
        return new Promise(function(resolve, reject) {
            fs.stat(path, function(err, stat) {
                if (err) reject(err)
                resolve(stat)
            })
        })
    }
    
    function findLargest(dir) {
        return readDir(dir)
            .then(function(files) {
                let promises = files.map(file => stat(path.join(dir, file)))
                return Promise.all(promises).then(function(stats) {
                    return { stats, files }
                })
            })
            .then(data => {
    
                let largest = data.stats
                    .filter(function(stat) { return stat.isFile() })
                    .reduce((prev, next) => {
                        if (prev.size > next.size) return prev
                        return next
                    })
    
                return data.files[data.stats.indexOf(largest)]
            })
    
    }
    

    使用方式为:

    
    findLargest('./')
    .then(function(filename) {
        console.log('largest file was:', filename);
    })
    .catch(function() {
        console.log(error);
    });
    

    Generator

    
    var fs = require('fs');
    var path = require('path');
    
    var co = require('co')
    
    var readDir = function(dir) {
        return new Promise(function(resolve, reject) {
            fs.readdir(dir, function(err, files) {
                if (err) reject(err);
                resolve(files)
            })
        })
    }
    
    var stat = function(path) {
        return new Promise(function(resolve, reject) {
            fs.stat(path, function(err, stat) {
                if (err) reject(err)
                resolve(stat)
            })
        })
    }
    
    function* findLargest(dir) {
        var files = yield readDir(dir);
        var stats = yield files.map(function(file) {
            return stat(path.join(dir, file))
        })
    
        let largest = stats
            .filter(function(stat) { return stat.isFile() })
            .reduce((prev, next) => {
                if (prev.size > next.size) return prev
                return next
            })
    
        return files[stats.indexOf(largest)]
    
    }
    

    使用方式为:

    
    co(findLargest, './')
    .then(function(filename) {
        console.log('largest file was:', filename);
    })
    .catch(function() {
        console.log(error);
    });
    

    Async

    
    var fs = require('fs');
    var path = require('path');
    
    var readDir = function(dir) {
        return new Promise(function(resolve, reject) {
            fs.readdir(dir, function(err, files) {
                if (err) reject(err);
                resolve(files)
            })
        })
    }
    
    var stat = function(path) {
        return new Promise(function(resolve, reject) {
            fs.stat(path, function(err, stat) {
                if (err) reject(err)
                resolve(stat)
            })
        })
    }
    
    async function findLargest(dir) {
        var files = await readDir(dir);
    
        let promises = files.map(file => stat(path.join(dir, file)))
        var stats = await Promise.all(promises)
    
        let largest = stats
            .filter(function(stat) { return stat.isFile() })
            .reduce((prev, next) => {
                if (prev.size > next.size) return prev
                return next
            })
    
        return files[stats.indexOf(largest)]
    
    }
    

    使用方式为:

    
    findLargest('./')
    .then(function(filename) {
        console.log('largest file was:', filename);
    })
    .catch(function() {
        console.log(error);
    });
    

    ES6 系列

    ES6 系列目录地址:https://github.com/mqyqingfeng/Blog

    ES6 系列预计写二十篇左右,旨在加深 ES6 部分知识点的理解,重点讲解块级作用域、标签模板、箭头函数、Symbol、Set、Map 以及 Promise 的模拟实现、模块加载方案、异步处理等内容。

    如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。

    来源:https://segmentfault.com/a/1190000016792362

  • 相关阅读:
    设计模式天天练。
    系统资料库msdb置疑或者不可用的解决方法
    依赖注入IOC
    重载、重写、隐藏的区别
    ASP.NET中的HttpWorkerRequest对像及其应用
    ASP.NET的错误处理机制
    Web.Config
    asp.net 2.0页面生命周期
    FileUpLoad控件上传大容量文件
    大文件上传
  • 原文地址:https://www.cnblogs.com/datiangou/p/10173192.html
Copyright © 2020-2023  润新知