• NodeJS实现同步的方法


     

    NodeJS被打上了单线程、非阻塞、事件驱动…..等标签。 在单线程的情况下,是无法开启子线程的。经过了很久的研究,发现并没有thread函数!!!但是有时候,我们确实需要“多线程”处理事务。nodeJS有两个很基础的api:setTimeout和setInterval。这两个函数都能实现“异步”。 nodeJS的异步实现:nodeJS有一个任务队列,在使用setInterval函数的时候,会每隔特定的时间向该任务队列增加任务,从而实现“多任务”处理。但是,“特定的时间”不代表是具体的时间,也有可能是会大于我们设定的时间,也有可能小于。 我们跑跑下面代码块

    setInterval(function() {
        console.log(new Date().getTime());
    }, 1000);

     

    输出的结果如下:

    1490531390640
    1490531391654
    1490531392660
    1490531393665
    1490531394670
    1490531395670
    1490531396672
    1490531397675
    ......

     

    我们可以看到,所有的时间间隔都是不一样的。时间的偏移不仅包含了间隔的1s,还包含了console.log()的耗时,以及new Date()的耗时。在大量的数据统计下,时间间隔近似于1s。

    问题来了,setInterval是能实现多任务的效果,但是怎样才能实现任务之间的同步操作呢?这里实现的方法是通过回调函数实现的。

    function a(callback) {
        // 模拟任务a耗时
        setTimeout(function() {
            console.log("task a end!");
            // 回调任务b
            callback();
        }, 3000);
    };
    
    function b() {
        setTimeout(function() {
            console.log("task b end!");
        }, 5000);
    }
    a(b);

     

    这里举了一个很简单的例子,就是将b方法的实现赋值给a方法的callback函数从而实现函数回调,但是会有个问题。假设a方法依赖于b方法,b方法依赖于c方法,c方法依赖于d方法…..也就意味着每个方法的实现都需要持有上一个方法的实例,从而实现回调。

    function a(b, c, d) {
        console.log("hello a");
        b(c, d);
    };
    
    function b(c, d) {
        console.log("hello b");
        c(d);
    };
    
    function c(d) {
        console.log("hello c");
        d()
    };
    
    function d() {
        console.log("hello d");
    };
    
    a(b, c, d);

     

    输出结果

    hello a
    hello b
    hello c
    hello d

     

    如果回调函数写的多了,会造成代码特别特别恶心。

    如果有类似于sync的函数能让任务顺序执行就更好了。终于找到了async这个库 $ npm instanll async

    async = require("async");
    a = function (callback) {
        // 延迟5s模拟耗时操作
        setTimeout(function () {
            console.log("hello world a");
            // 回调给下一个函数
            callback(null, "function a");
        }, 5000);
    };
    
    b = function (callback) {
        // 延迟1s模拟耗时操作
        setTimeout(function () {
            console.log("hello world b");
            // 回调给下一个函数
            callback(null, "function b");
        }, 1000);
    };
    
    c = function (callback) {
        console.log("hello world c");
        // 回调给下一个函数
        callback(null, "function c");
    };
    
    // 根据b, a, c这样的顺序执行
    async.series([b, a, c], function (error, result) {
        console.log(result);
    });

     

    注释基本能够很好的理解了,我们看看输出

    hello world b
    hello world a
    hello world c
    [ 'function b', 'function a', 'function c' ]

     

    上面的基本async模块的实现的如果了解更多关于async模块的使用,可以点击:查看详情

    其实nodeJS基本api也提供了异步实现同步的方式。基于Promise+then的实现

    sleep = function (time) {
        return new Promise(function () {
            setTimeout(function () {
                console.log("end!");
            }, time);
        });
    };
    
    console.log(sleep(3000));

     

    输出结果为:

    Promise { <pending> }
    end!

     

    可以看出来,这里返回了Promise对象,直接输出Promise对象的时候,会输出该对象的状态,只有三种:PENDING、FULFILLED、REJECTED。字面意思很好理解。也就是说Promise有可能能实现我们异步任务同步执行的功能。我们先用Promise+then结合起来实现异步任务同步操作。

    
    sleep = function () {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                console.log("start!");
                resolve();
            }, 1000);
        })
            .then(function () {
                setTimeout(function () {
                    console.log("end!");
                }, 2000);
            })
            .then(function () {
                console.log("end!!");
            })
    };
    console.log(sleep(1000));

     

    输出结果:

    Promise { <pending> }
    start!
    end!!
    end!

     

    在new Promise任务执行完后,调用了resolve才会执行所有的then函数,并且这些then函数是异步执行的。由输出结果可以知道。(如果所有then是顺序执行的应该是end! -> end!!)。但是上述也做到了两个异步任务之间顺序执行了。

    不过,还有更加优雅的方式:使用async+await。

    display = function(time, string) {
        return new Promise(function (resovle, reject) {
            setTimeout(function () {
                console.log(string);
                resovle();
            }, time)
        });
    };
    
    // 执行顺序:b a c
    fn = async function () {
        // 会造成阻塞
        await display(5000, "b");
        await display(3000, "a");
        await display(5000, "c");
    }();

     

    输出结果:

    b
    a
    c

     

    由于这里时间输出比较尴尬,只能通过我们来感知,本人通过个人“感知”知道了在display b过度到display a的时候大概用了3s,再过度到display c的时候大概用了5s

  • 相关阅读:
    博客园 如何给上传的图片添加水印?
    今天把这三篇文章看完(DeepFM/NN/BN)
    今天看了这篇文章,还是要提前做好准备
    POJ1988Cube Stacking
    AcWing 1250. 格子游戏
    POJ 1962 Corporative Network [带权并查集]模板
    AcWing 477. 神经网络
    埃拉托色尼筛法和欧拉筛法
    AcWing 1252. 搭配购买
    AcWing 2128. 狡猾的商人
  • 原文地址:https://www.cnblogs.com/juehai/p/9527731.html
Copyright © 2020-2023  润新知