Node.js学习笔记(3)——关于回调函数和函数的回调
说明:本人是node.js的初学者,尝试向别人解释这是怎么回事是自我学习的一个好方法。如果你发现有些地方并不是那么正确,欢迎提出来让我知道以便修正,共同进步,谢过^_^。 欢迎交流,本人微博:http://weibo.com/bitsea
很多地方都涉及到函数的回调,在这里简单说一下什么是函数的回调。
回调函数就是回来再调用的函数。
基于js的单线程执行代码的风格,回调是必须的选择。也可以说是一种不得已而为之的选择吧,回调无疑增加了代码的复杂性,使其变得难读、难理解,难维护。但是,在解决实际问题的时候,回调又非常有效。下面举例说明:
我们要读取一个很大的文件,但是我们有不需要立刻获得读取的结果,并且,我们可不只有读取文件这个任务,我们还要执行其他的代码。这个时候,我们就需要回调函数过来帮忙。
var fs=require(“fs”);
fs.readFile(‘text.txt’,utf-8,function(err,result){
If(err) throw err;
//result就是读取出来的数据
});
console.log(‘下一项任务’);
这样一来,就可以把读文件那个任务放一放了,我们完成完我们的下一个任务的时候,闲得慌的时候再回来执行它不晚,有错误就抛出来。
这个方法在很多的node.js工程上面有大量的应用(就我接触的而言),复制一段项目里面的几句代码(有关查询数据库):
conn.query("select login,qq,phone,type from user where name='"+myphone+"'",function(err, rowss, fields) { if (err) {console.log(err);res.end();return;} if(rowss.length<1) {res.end("{{}}alert{}操作失败,你的手机没有登记过{{}}");return;}
这里的function就是回调函数。
我又在另一篇国外的人写的文章,他从客户端的角度阐述了为什么采取回调函数的解决方案是node的必然选择:我们知道,php为每一个客户端开辟一个新的线程用于服务新的请求,但是由于node的“先天残疾”,如果前一个请求需要花费5s,后一个请求就不得不等待5s!这是不能忍的,我在抢票回家过年好咩!!这个叫阻塞,前一个阻塞掉后一个。我们要把它变成一个非阻塞的,每个人都有公平的机会抢到回家的票。于是就用到回调函数。
文章中还打了一个很有意思的比喻,这里摘抄过来:
你在一个狭窄的道路上开车,前面有一个SB在停着打电话,很忙的样子(阻塞代码)使你不能到达目的地,这样你必须等这个SB打完电话把车启动起来才 能继续(有人可能想,用板砖干他丫的,但从程序角度来说,把他丫干死,前面少了一个司机,你要等警察来拖走或者自己先开走他的后再开自己的车,外加法律责 任,代价是很大滴,这叫破坏模型,比阻塞模型的代价还大)。
想像一下如果这条路上有紧急停车带,前面那SB司机可以变得不SB,先把车停在紧急停车带打电话。把路让出来让你先继续你的旅程。当那个不再SB的 司机打完电话之后也可以回到主干上来继续前行,还避免了可能碰到的板砖型程序员而导致血光之灾,皆大欢喜。这跟异步调用很像,在同一时间同一主干上跑多辆车。
非常有趣,isn’t it?
咳咳,好了言归正传。上代码(三段)说明问题!!
var http = require('http'); var url = require('url'); http.createServer(function (request, response) { response.writeHead(200, {'Content-Type': 'text/plain'}); if( url.parse(request.url).pathname == '/wait' ){ var startTime = new Date().getTime(); while (new Date().getTime() < startTime + 15000); response.write('Thanks for waiting!'); } else{ response.write('Hello!'); } response.end(); }).listen(8080); console.log('Server started');
代码读起来不难,创建了可一个服务器,监听8080端口。我们运行node这个文件之后,在浏览器里面输入localhost:8080/wait回车,代码开始起作用,十五秒之后蹦出来一句话。
这不能说明什么问题。但是,在你按下回车之后的15秒内,另一个客户需要访问这个这个服务器的时候,也需要等待你完成之后才轮到他。黄花菜都凉了!
下一段代码(包含两个文件):
block.js:
var startTime = new Date().getTime(); while (new Date().getTime() < startTime + 10000);
main.js:
var http = require('http'); var url = require('url'); var cp = require('child_process'); function onRequest(request, response) { var pathname = url.parse(request.url).pathname; if( pathname == '/wait' ){ cp.exec('node block.js', myCallback); } else{ response.writeHead(200, {'Content-Type': 'text/plain'}); response.write('Hello!\n'); response.end(); } console.log('New connection'); function myCallback(){ response.writeHead(200, {'Content-Type': 'text/plain'}); response.write('Thanks for waiting!\n'); response.end(); } } http.createServer(onRequest).listen(8080); console.log('Server started');
两段代码类似,这个多申请了一个cp子进程,用于在用户访问wait域名的时候调用block.js。在其他用户访问非wait域名的时候,服务器仍然能及时响应hello,这个时候道路还是通畅的,原因就是上一个sb还在紧急停车带打电话呢!这一切都归功于cp.exec('node block.js', myCallback);里面的回调函数:myCallback。.exec函数有两个参数,一个调用block.js,另外一个执行回调函数。
第三段代码(一个读取文件的程序):
var http = require('http'); var fileSystem = require('fs'); http.createServer(function (request, response) { response.writeHead(200, {'Content-Type': 'text/plain'}); var read_stream = fileSystem.createReadStream('myfile.txt'); read_stream.on('data', writeCallback); read_stream.on('close', closeCallback); function writeCallback(data){ response.write(data); } function closeCallback(){ response.end(); } }).listen(8080); console.log('Server started');
这里使用了内置的文件操作模块,使用函数.createReadStream()读取文件。
总结:
无论你是否有需要执行一个耗时很长的程序与否,你都应该使用非阻塞模型,并且记住,正确使用回调和异步可以让代码的速度和稳定性都能得到提高。
Node.js学习笔记(3)——关于回调函数和函数的回调的更多相关文章
- Node.js学习笔记(2):基本模块
Node.js学习笔记(2):基本模块 模块 引入模块 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式.在No ...
- 一点感悟:《Node.js学习笔记》star数突破1000+
写作背景 笔者前年开始撰写的<Node.js学习笔记> github star 数突破了1000,算是个里程碑吧. 从第一次提交(2016.11.03)到现在,1年半过去了.突然有些感慨, ...
- Node.js学习笔记(3):NPM简明教程
Node.js学习笔记(3):NPM简明教程 NPM常用操作 更新NPM版本 npm install npm -g -g,表示全局安装.我们可以指定更新版本,只需要在后面填上@版本号即可,也可以输入@ ...
- 系列文章--Node.js学习笔记系列
Node.js学习笔记系列总索引 Nodejs学习笔记(一)--- 简介及安装Node.js开发环境 Nodejs学习笔记(二)--- 事件模块 Nodejs学习笔记(三)--- 模块 Nodejs学 ...
- Node.js学习笔记(1):Node.js快速开始
Node.js学习笔记(1):Node.js快速开始 Node.js的安装 下载 官方网址:https://nodejs.org/en/ 说明: 在Windows上安装时务必选择全部组件,包括勾选Ad ...
- Node.js学习笔记(4):Yarn简明教程
Node.js学习笔记(4):Yarn简明教程. 引入Yarn NPM是常用的包管理工具,现在我们引入是新一代的包管理工具Yarn.其具有快速.安全.可靠的特点. 安装方式 使用npm工具安装yarn ...
- Node.js学习笔记(4)——除了HTTP(服务器和客户端)部分
很多node入门的书里面都会在介绍node特性的时候说:单线程,异步式I/O,事件驱动. Node不是一门语言,它是运行在服务器端的开发平台,官方指定语言为javascript. 阻塞和线程: 线程在 ...
- node.js学习笔记(二)——回调函数
Node.js 异步编程的直接体现就是回调. 那什么是回调呢?回调指的是将一个函数作为参数传递给另一个函数,并且通常在第一个函数完成后被调用.需要指明的是,回调函数不是由该函数的实现方直接调用,而是在 ...
- Node.js学习笔记(一)
1.回调函数 node是一个异步事件驱动的平台,所以在代码中我们经常需要使用回调函数. 例: setTimeout(function(){ console.log('callback is calle ...
随机推荐
- PE
不是projecteuler,我想说的是projecteuclid..似乎是一个有很多数学文献的网站..? PE541似乎是一道很有趣的题目,有一个暴力大概就是首先转化一下模型变成找\(\sum_{x ...
- AspNetPager分页控件官方网站
原文发布时间为:2009-12-04 -- 来源于本人的百度文章 [由搬家工具导入] http://www.webdiyer.com/AspNetPager
- 【Visual Studio】解决错误 fatal error C1010: unexpected end of file while looking for precompiled head(转)
原文转自 http://blog.csdn.net/liuqiyao_01/article/details/38867145 在编译VS时候,出现fatal error C1010: unexpect ...
- LeetCode总结【转】
转自:http://blog.csdn.net/lanxu_yy/article/details/17848219 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近完成了www.leetco ...
- Delphi 半透明窗体,窗体以及控件透明度
很简单了 现在,适用所有控件和窗体: delphi设置窗口透明 form1.AlphaBlend :=true; //透明form1.AlphaBlendValue :=180; //透明度form1 ...
- LeetCode OJ-- Maximum Subarray @
https://oj.leetcode.com/problems/maximum-subarray/ 给了一个数组一列数,求其中的连续子数组的最大和. O(n)复杂度 class Solution { ...
- 腾讯云使用liveRoom开启直播时,报“房间已存在”错误?
利用腾讯云roomService服务,移动直播,创建房间api,CreateRoom时有时报“房间已存在”错误. 分析流程发现,CreateRoom会传入roomId到roomService后台,后台 ...
- PHP生成随机码
前几天,做了个小小的实验,生成了一组数据,数据要求是包含1000个元素,每个元素为10个随机的数字加字母的组合. 嗨呀,说写就写,然后用for循环生成了一组数据,看起来还不错,先把代码贴上来. //随 ...
- Codeforces Round #324 (Div. 2) Dima and Lisa 哥德巴赫猜想
原题链接:http://codeforces.com/contest/584/problem/D 题意: 给你一个奇数,让你寻找三个以内素数,使得和为这个奇数. 题解: 这题嘛...瞎比搞搞就好,首先 ...
- window环境下使用PHP OpenSSL扩展函数返回false的原因
window环境下使用PHP OpenSSL扩展函数返回false的原因(openssl_pkey_new) 使用的开发环境是PHPstudy ,在使用OpenSSL的函数openssl_pkey_n ...