返回顶部
首页 > 资讯 > 前端开发 > node.js >详谈nodejs异步编程
  • 153
分享到

详谈nodejs异步编程

nodejs 2022-06-04 17:06:57 153人浏览 薄情痞子
摘要

目前需求中涉及到大量的异步操作,实际的页面越来越倾向于单页面应用。以后可以会使用backbone、angular、knockout等框架,但是关于异步编程的问题是首先需要面对的问题。随着node的兴起,异步

目前需求中涉及到大量的异步操作,实际的页面越来越倾向于单页面应用。以后可以会使用backbone、angular、knockout等框架,但是关于异步编程的问题是首先需要面对的问题。随着node的兴起,异步编程成为一个非常热的话题。经过一段时间的学习和实践,对异步编程的一些细节进行总结

1.异步编程的分类

解决异步问题方法大致包括:直接回调、pub/sub模式(事件模式)、异步库控制库(例如async、when)、promise、Generator等。
1.1 回调函数

回调函数是常用的解决异步的方法,经常接触和使用到,易于理解,并且在库或函数中非常容易实现。这种也是大家接使用异步编程经常使用到的方法。

但是回调函数的方式存在如下的问题:

1. 可能形成万恶的嵌套金字塔,代码不易阅读;

2. 只能对应一个回调函数,在很多场景中成为一个限制。

1.2 pub/sub模式(事件)

该模式也称为事件模式,是回调函数的事件化,在Jquery等类库中非常常见。

事件发布订阅者模式本身并无同步与异步调用的问题,但是在node中,emit调用多半是伴随事件循环而异步触发的。该模式常用来解耦业务逻辑,事件发布者无须关注注册的回调函数,也不用关注回调函数的个数,数据通过消息的方式可以很灵活的传递。

该模式的好处是:1. 便于理解;2. 不再局限于一个回调函数。

不好的地方时:1. 需要借助类库; 2.事件与回调函数的顺序很重要

var img = document.querySelect(#id);

img.addEventListener('load', function() {

  // 图片加载完成

    ......

});

img.addEventListener('error', function() {

  // 出问题了

  ......

});

  上述代码存在两个问题:

a. img实际已经加载完成,此时才绑定load回调函数,结果回调不会执行,但依然希望执行该对应回调函数。

var img = document.querySelect(#id);

function load() {

  ...

}

if(img.complete) {

  load();

} else {

  img.addEventListener('load', load);

}

img.addEventListener('error', function() {

  // 出问题了

  ......

});

   b. 无法很好处理存在异常

结论:事件机制最适合处理同一个对象上反复发生的事情,不需要考虑当绑定回调函数之前事件发生的情况。

1.3 异步控制库

目前的异步库主要有Q、when.js、win.js、RSVP.js等。

这些库的特点是代码是线性的,可以从上到下完成书写,符合自然习惯。

不好的地方也是风格各异,不便于阅读,增加学习成本。

1.4 Promise

Promise翻译成中文为承诺,个人理解是异步完成之后,就会给外部一个结果(成功或失败),并承诺结果不再发生改变。换句话就是Promise反应了一个操作的最终返回结果值(A promise represents the eventual value returned from the single completion of an operation)。目前Promise已经引入到es6规范里面,Chrome、firefox等高级浏览器已经在内部实现了该原生方法,使用起来相当方便。

下面从如下几个方面来解析Promise的特点:

1.4.1 状态

包含三种状态:pending、fulfilled、rejected,三种状态只能发生两种转换(从pending--->fulfilled、pending—>rejected),并且状态的转换仅能发生一次。

查看图片

1.4.2 then方法

then方法用于指定异步事件完成之后的回调函数。

这个方法可以说是Promise的灵魂方法,该方法让Promise充满了魔力。有如下几个具体表现:

a) then方法返回Promise。这样就实现了多个异步操作的串行操作。

查看图片

关于上图中黄圈1的对value的处理是Promise里面较为复杂的一个地方,value的处理分为两种情况:Promise对象、非Promise对象。

当value 不是Promise类型时,直接将value作为第二个Promise的resolve的参数值即可;当为Promise类型时,promise2的状态、参数完全由value决定,可以认为promsie2完全是value的傀儡,promise2仅仅是连接不同异步的桥梁。

查看图片

Promise.prototype.then = function(onFulfilled, onRejected) {

    return new Promise(function(resolve, reject) {           //此处的Promise标注为promise2

        handle({

            onFulfilled: onFulfilled,

            onRejected: onRejected,

            resolve: resolve,

            reject: reject

        })

    });

}

function handle(deferred) {

    var handleFn;

    if(state === 'fulfilled') {

        handleFn = deferred.onFulfilled;

    } else if(state === 'rejected') {

        handleFn = deferred.onRejected;

    }

    var ret = handleFn(value);

    deferred.resolve(ret);                           //注意,此时的resolve是promise2的resolve

}

function  resolve(val) {

    if(val && typeof val.then === 'function') {

        val.then(resolve);                           // if val为promise对象或类promise对象时,promise2的状态完全由val决定

        return;

    }

    if(callback) {                                    // callback为指定的回调函数

        callback(val);

    }

}

  b)实现了多个不同异步库之间的转换。

在异步中存在一个叫thenable的对象,就是指具有then方法的对象,只要一个对象对象具有then方法,就可以对其进行转换,例如:

var deferred = $('aa.ajax');      // !!deferred.then  === true

var P = Promise.resolve(deferred);

p.then(......)

1.4.3 commonJS Promise/A规范

目前关于Promise的规范存在Promise/A和Promise/A+规范,这说明关于Promise的实现是挺复杂的。

then(fulfilledHandler, rejectedHandler, progresshandler)

1.4.4 注意事项

一个Promise里面的回调函数是共享value的,在结果处理中value作为参数传递给相应的回调函数,如果value是对象,那就要小心不要轻易修改value的值。

var p = Promise.resolve({x: 1});

p.then(function(val) {

    console.log('first callback: ' + val.x++);

});

p.then(function(val) {

    console.log('second callback: ' + val.x)

})

// first callback: 1

// second callback: 2

1.5 Generator

上面所有的方法均是基于回调函数来完成异步操作的,无非是对回调函数进行封装而已。ES6里面提出了Generator,增加了解决异步操作的途径,不再依据回调函数来完成。

Generator最大的特点就是可以实现函数的暂停、重启,这个特性非常有利于解决异步操作。将Generator的暂停与promise的异常处理结合起来,可以比较优雅地解决异步编程问题。具体实现参考:Kyle Simpson

2. 异步编程存在的问题

2.1 异常处理

a) 异步事件包括两个环节:发出异步请求、结果处理,这两个环节通过event loop来连接起来。那么try catch来进行异常捕获的时候就需要分来捕获。

try {

    asyncEvent(callback); 

} catch(err) {

    ......

}

上述代码是无法捕获callback里面的异常,只能获取发出请求环节的异常。这样就存在问题:假如请求的发出和请求的处理是两个人完成的,那么在异常处理的时候就存在问题?

b)promise实现异常的传递,这带来一些好处,在实际项目中保证代码不被阻塞。但是如果异步事件比较多的时候,不容易找出到底是那个异步事件产生了异常。

// 场景描述: 在CRM里面展示价格的报警信息,其中包含竞对的信息。但是获取竞对的信息时间比较长,后端为了避免慢查询,就把一条记录拆成两块分别获取。

// 第一步:获取价格报警信息,除了竞对信息

function getPriceAlarmData() {

    return new Promise(function(resolve) {

        Y.io(url, {

            method: 'get',

            data: params,

            on: function() {

                success: function(id, data) {

                    resolve(alarmData);

                }

            }

        });

    });

}

// 得到报警信息后,在去获取竞对信息

getPriceAlarmData().then(function(data) {

    // 数据渲染,除了竞对信息

    render(data);

    return new Promise(function(resolve) {

        Y.io(url, {

            method: 'get',

            data: {alarmList: data},

            on: function() {

                success: function(id, compData) {

                    resolve(compData);

                }

            }

        });

    });

})      //  获取完所有数据后进行竞对信息的渲染

.then(function(data) {

    // 渲染竞对信息

    render(data)

}, function(err) {

    // 异常处理

    console.log(err);

});

可以把上述代码转换成如下:

try{

    // 获取除竞对以外的报警信息

    var alarmData = alarmDataExceptCompare();

    render(alarmData);

    // 根据报警信息查询竞对信息

    var compareData = getCompareInfo(alarmData);

    render(compareData);

} catche(err) {

    console.log(err.message);

}

在上述例子中把异常处理放到最后进行处理,这样当其中存在某个环节出现异常,我们无法准确知道到底是哪个事件产生的。

2.2 jQuery.Deferred 的问题

jQuery中也实现了异步操作,但是在实现上不符合promise/A+规范,主要表现在以下几个方面:

a. 参数的个数:标准的Promise只能接受一个参数,而jQuery中则可以传递多个参数

function asyncInJQuery() {

    var d = new $.Deferred();

    setTimeout(function() {

        d.resolve(1, 2);

    }, 100);

    return d.promise()

}

asyncInJQuery().then(function(val1, val2) {

    console.log('output: ', val1, val2);

});

// output: 1 2

b. 结果处理中异常的处理

function asyncInPromise() {

      return new Promise(function(resolve) {

        setTimeout(function() {

          var JSONStr = '{"name": "mt}';

          resolve(jsonStr);

        }, 100);

      });

  }

  asyncInPromise().then(function(val) {

      var d = JSON.parse(val);

      console.log(d.name);

  }).then(null, function(err) {

    console.log('show error: ' + err.message);

  });

// show error: Unexpected end of input

function asyncInJQuery() {

    var d = new $.Deferred();

    setTimeout(function() {

        var jsonStr = '{"name": "mt}';

        d.resolve(jsonStr);

    }, 100);

    return d.promise()

}

asyncInJQuery().then(function(val) {

    var d = JSON.parse(val);

    console.log(d.name);

}).then(function(v) {

    console.log('success: ', v.name);

}, function(err){

    console.log('show error: ' + err.message);

});

//Uncaught SyntaxError: Unexpected end of input

从中可以看出,Promise对回调函数进行了结果处理,可以捕获回调函数执行过程中的异常,而jQuery.Deferred却不可以。

--结束END--

本文标题: 详谈nodejs异步编程

本文链接: https://lsjlt.com/news/12014.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 详谈nodejs异步编程
    目前需求中涉及到大量的异步操作,实际的页面越来越倾向于单页面应用。以后可以会使用backbone、angular、knockout等框架,但是关于异步编程的问题是首先需要面对的问题。随着node的兴起,异步...
    99+
    2022-06-04
    nodejs
  • 浅谈node.js中async异步编程
    1.什么是异步编程? 异步编程是指由于异步I/O等因素,无法同步获得执行结果时, 在回调函数中进行下一步操作的代码编写风格,常见的如setTimeout函数、ajax请求等等。 示例: for (v...
    99+
    2022-06-04
    浅谈 node async
  • 浅谈Node异步编程的机制
    本文介绍了Node异步编程,分享给大家,具体如下: 目前的异步编程主要解决方案有: 事件发布/订阅模式 Promise/Deferred模式 流程控制库 事件发布/订阅模式 Node自身提供...
    99+
    2022-06-04
    浅谈 机制 Node
  • 浅谈 PHP 函数的异步编程
    在 php 中,异步编程允许在不阻塞执行流的情况下执行耗时任务。实现异步编程的技术包括:回调函数:函数指针,在另一个函数执行完成后执行代码。协程:轻量级多任务机制,允许在同一线程中切换多...
    99+
    2024-05-05
    php 异步编程
  • NodeJs异步编程的含义是什么
    本文小编为大家详细介绍“NodeJs异步编程的含义是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“NodeJs异步编程的含义是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识...
    99+
    2024-04-02
  • 详解python之异步编程
    目录一、异步编程概述二、python的异步框架模型三、顺序执行多个可重叠的任务四、异步化同步代码五、使用多线程克服具体任务的异步限制总结一、异步编程概述 异步编程是一种并发编程的模式...
    99+
    2024-04-02
  • Nodejs异步编程中的Promise有什么作用
    这篇文章主要介绍“Nodejs异步编程中的Promise有什么作用”,在日常操作中,相信很多人在Nodejs异步编程中的Promise有什么作用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,...
    99+
    2024-04-02
  • rust异步编程详细讲解
    目录简化版本 Future理解Future的模型async/awit 使用简化版本 Future // wake 函数 reactor发现状态是ready 通知executor 函数...
    99+
    2022-12-16
    rust异步编程 rust异步原理
  • nodejs教程之异步I/O
    前言 在我映像中,异步最早出现与ajax,当时我还在搞.net,然后.net居然出了一个异步的控件...... 虽然我最后知道了他不是异步的......然后,前端异步用得特别多,如果不是异步的程序,你都不好...
    99+
    2022-06-04
    教程 nodejs
  • Java 异步编程 (5 种异步实现方式详解)
    同步操作如果遇到一个耗时的方法,需要阻塞等待,那么我们有没有办法解决呢?让它异步执行,下面我会详解异步及实现 @mikechen 目录 什么是异步?一、线程异步二、Future异步三、CompletableFuture异步四、Spring...
    99+
    2023-09-02
    java jvm 数据库
  • 详细谈谈NodeJS进程是如何退出的
    目录前言主动退出 Exceptions, Rejections 和 Emitted Errors 信号 小结 前言 有几种因素可以导致 NodeJS 进程退出。在这些因素中,有些是可...
    99+
    2024-04-02
  • 详解nodejs中的异步迭代器
    目录前言什么是异步迭代器作为异步迭代器流调用有分页功能的 API前言 从 Node.jsv10.0.0 开始,异步迭代器就出现中了,最近它们在社区中的吸引力越来越大。在本文中,我们将...
    99+
    2024-04-02
  • C#异步编程之async/await详解
    目录概述C#异步编程用法async/await和Task简介asyncawaitTask其他实现原理剖析实现原理示例概述 异步这个概念在不同语境下有不同的解释,比如在一个单核CPU里...
    99+
    2023-03-11
    C#异步编程async await C#异步编程 C# async await
  • JS异步编程Promise对象详解
    1、单线程模型 单线程模型指的是,JavaScript 只在一个线程上运行。也就是说,JavaScript 同时只能执行一个任务,其他任务都必须在后面排队等待。注意,JavaScri...
    99+
    2024-04-02
  • Java 的异步编程 (5 种异步实现方式详解)
    一、线程异步 创建一个异步线程 public class AsyncThread extends Thread{ @Override public void run() { System.out.println("...
    99+
    2023-09-03
    java jvm 开发语言
  • asyncio异步编程之Task对象详解
    目录1.Task对象的作用2.如何创建task对象3.示例一(目前不推荐这种写法)4.示例25.示例3(算是以上示例2的简化版)总结1.Task对象的作用 可以将多个任务添加到事件循...
    99+
    2024-04-02
  • Java异步编程工具Twitter Future详解
    目录异步编程(Twitter Future)为啥要异步基本用法1、封装计算逻辑,异步返回。2、异步计算结果串联异步处理3、并行多个异步任务,统一等待结果4、异步错误处理Twitter...
    99+
    2024-04-02
  • 详解SpringBoot如何开启异步编程
    目录一、什么是异步?二、为什么要使用异步编程?三、SpringBoot开启异步编程1、有返回值的异步方法2、@Async使用的线程池3、SpringBoot使用的默认线程池源码解析4...
    99+
    2023-05-17
    SpringBoot异步编程 SpringBoot异步
  • JavaScript异步编程中async函数详解
    目录async函数await 表达式async使用形式async读取文件async发送AJAX请求与生成器(Generator)相比async函数 async函数的返回值为 prom...
    99+
    2022-11-13
    JavaScript async JavaScript异步编程 JS async
  • C#异步编程async/await用法详解
    异步函数简介 一般指 async 修饰符声明得、可包含await表达式得方法或匿名函数。 声明方式 异步方法的声明语法与其他方法完全一样, 只是需要包含 async 关键字。asyn...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作