nodejs异步和回调

什么是异步

比如早上起来,我需要洗口3min,烧水3min,冲牛奶,做这三件事的过程我们分析一,假设烧水只需要按一下开关,冲牛奶不耗时
异步:烧水,洗口–>冲牛奶=3min
同步:洗口–>烧水–>冲牛奶=6min

nodejs机制

nodejs是单线程语言,所有事件都是放在一个堆栈中去进行,必须把当前函数栈清空才会去执行后面代码,但是是不是就不能做到异步呢,也不是,它有特例,nodejs针对io操作和部分网络请求提供了异步操作,接下来看一下下面例子

同步例子

function runSync() {
      for (var i = 0; i < 5; i++) {
        var waitUnit = new Date().getTime() + 1000;
        while (waitUnit > new Date().getTime()) {

        }
        console.log('doing');
      }
}
runSync();
console.log('end');

输出结果:

doing
doing
doing
doing
doing
end

以上就是一个同步的例子,必须等待函数runSync执行完成才会执行下面的log

异步例子

var fs = require('fs')
function read_file(path){
    fs.readFile(path,"UTF-8",function(err,data){
      if(data){
        resolve(data);
        console.log('resolve');
      }else{
        reject(err);
        console.log('reject');
      }
    });
}

read_file('/Users/jemy/Desktop/player_sdk2.1.5.zip');
console.log('end');

输出信息如下:

end
resolve

发现先打印了end,这个是为什么呢,因为node内部的io会将readFile这个事件起一个辅助线程,然后就不管它了,而readFile是一个耗时操作,所以会先打印log(‘end’),当readFile这个耗时操作执行完时会回调告知已经执行完毕

nodejs优缺点

比如早期的小白我是这样写代码的(在武汉那种地方,都是java+html+js所谓的全栈)

var name = '';
$.ajax({
  ...
  success:function(data){name=data.name},
});
$("#name").html(name);

最后发现无论如何都不能在html中写进name值
缺点:
1.因为是单线程,一个地方挂了,整个都gg
2.不适用于非IO的复杂性计算,谁在那一直等着你返回
优点:
1.对业务量较小但是IO操作频繁的能够得到充分利用,适用于高并发
2.单线程非阻塞IO了解一下
异步的坑比较多,比如上面我写到的早期的我写代码出现的bug,但是掌握了哪些是异步操作用起来可谓得心应手

回调

回调这个比较神奇,nodejs很多实现基本上就是异步+回调,那么如何写一个回调函数呢
作为一个由java转向Android的程序员,曾经真是花了不少时间去研究Java中回调的写法 ?
我们直接看一个例子和其中的注释吧

//别人定义的接口--同步
function printAsTime(name,stop) {
    for(var i = 0;i<5;i++){
    var waitUnit = new Date().getTime()+1000;
      while(waitUnit>new Date().getTime()){

      }
      console.log(name);//3.log一下传进来的参数
    }
    try {
      var str = stop('arg1','arg2','arg3');//4.执行回调函数到调用处
      console.log(str);//7.内部函数接收到来自客户端的返回并打印一下
    } catch (err) {
      console.log('客户端未调用回调方法');//
    }
}


//客户端测试该方法的回调
// function stopPrint(ret01,ret02,ret03){
//   console.log('stop-返回参数'+ret01+'-'+ret02+'-'+ret03);
// }
// console.log('start-function');
// //printAsTime('zhangwei',stopPrint);
// printAsTime('zhangwei');
// console.log('stop-function');

//ES6中定义的箭头指向的匿名函数
console.log('start-function'); //1.start
printAsTime('zhangwei',(ret01,ret02,ret03)=>{//2.执行printAsTime函数
    console.log('stop-返回参数: '+ret01+'-'+ret02+'-'+ret03);//5.匿名函数获取回调返回值提供给客户端处理
    return '回调结束';//6.客户端处理完接口返回的值后还可以再次将客户处理结果返回给内部函数
})
console.log('stop-function');//8.结束

结果如下:

start-function
zhangwei
zhangwei
zhangwei
zhangwei
zhangwei
stop-返回参数: arg1-arg2-arg3
回调结束
stop-function
### 异步编程的概念特点 异步编程是一种处理任务的方式,允许程序在等待某个操作完成时继续执行其他任务。Node.js通过其事件驱动模型非阻塞I/O机制实现了高效的异步编程[^2]。这意味着在进行文件读写、网络请求等耗时操作时,Node.js不会阻塞主线程,而是通过回调函数或Promise来处理操作的结果。 ### 回调函数 回调函数是Node.js中最基本的异步编程模式。当一个异步操作完成后,会调用一个指定的函数来处理结果。这种方式简单直接,但可能会导致代码难以维护,尤其是在嵌套多个异步操作时,容易形成所谓的“回调地狱”(Callback Hell)。 ```javascript fs.readFile('example.txt', 'utf8', function(err, data) { if (err) { return console.log(err); } console.log(data); }); ``` ### Promise 为了改善回调地狱的问题,Promise提供了一种更清晰的方式来处理异步操作。Promise对象表示一个异步操作的最终完成(或失败)及其结果值。它提供了`.then()``.catch()`方法来处理成功失败的情况。 ```javascript let promise = new Promise((resolve, reject) => { setTimeout(() => resolve("Done!"), 1000); }); promise.then(result => { console.log(result); // 输出 "Done!" }).catch(error => { console.log(error); }); ``` ### async/await async/await是基于Promise的一种语法糖,它使得异步代码看起来更像是同步代码,从而提高了代码的可读性可维护性。使用`async`关键字定义的函数返回一个Promise,而`await`关键字只能在`async`函数内部使用,用于等待Promise解析。 ```javascript async function fetchData() { try { let response = await fetch('https://api.example.com/data'); let data = await response.json(); console.log(data); } catch (error) { console.error('Error fetching data: ', error); } } fetchData(); ``` ### 最佳实践 - **错误处理**:无论使用哪种异步编程模式,都应该妥善处理可能出现的错误。对于Promise,可以使用`.catch()`方法捕获异常;而在`async/await`中,则可以通过`try...catch`语句块来处理错误。 - **避免回调地狱**:尽量使用Promise或`async/await`替代传统的回调函数,以保持代码的整洁易于理解。 - **资源管理**:确保在异步操作完成后正确释放相关资源,如关闭数据库连接或清理临时文件。 ### 示例 下面是一个使用`async/await`进行HTTP请求的例子: ```javascript async function getJson(url) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error(`Fetch error: ${error.message}`); } } getJson('https://api.example.com/data') .then(data => console.log(data)) .catch(error => console.error(error)); ``` 以上示例展示了如何利用现代JavaScript特性来简化异步编程,并提高代码的可读性健壮性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值