http概念进阶

极客拾贝手
• 阅读 3024

什么是回调?
回调是异步编程的基础方法,当需要按照顺序执行异步逻辑的时候,一般采取后续传递的方式,也就是将后续逻辑封装在回调函数中作为起始函数的参数,逐层去嵌套。

function lean(something){
   console.log(something)
}

function we(callback,something){
    something+=' is cool'
    callback(something)//结果传递给回调函数

}

we(lean,'node')//具名函数

we(function(something){//传递匿名函数
    console.log(something)

},'jade')

什么是同步
同步就是执行一个任务,后一个任务等待前一个任务结束,然后再执行,程序执行的顺序与任务的排列顺序是一致的,比如js是单线程的,因此js代码是按照顺序执行的,即便是js同步下载多个文件,也得按照顺序执行,一旦js里面出现死循环的代码,那么页面就会被阻塞在这个地方,后面的js代码就不会被执行到 比如打电话预约座位,发现没有座位了,店员就挂电话开始查找有没有座位,查找,查找...等待一会儿之后,店员通过回电话,开始执行回调函数来解决你的问题(是否有座位)。
什么是异步
异步执行任务,如果发现任务阻塞,js执行setTimeOut,毫秒时间作为其中的一个参数,然后自动执行另外一个函数,不会一直等待。

//代码按照顺序执行,结果看就是1
var c = 0
function printIt(){
    console.log(c)
}

function plus(){
    c+=1
}
plus()
printIt()
//加上耗时操作,没有加回调函数,结果不改变
var c = 0
function printIt(){
    console.log(c)
}

function plus(){//加上耗时操作,没有调用回调函数,所以js一直阻塞在这里,不能执行,所以结果还是 0,没有变化。
    setTimeout(function(){
          c+=1
    },1000)

}
plus()
printIt()
var c = 0
function printIt(){
    console.log(c)
}
function plus(callback){
    setTimeout(function(){
          c += 1
          callback();//5s之后timeout,开始调用回调函数
    },5000)
}

plus(printIt)

什么是io
磁盘的写和读,在nodejs里面就是为文件系统,数据库资源提供接口,发送请求的时候,不用等待硬盘,当硬盘准备好了,非阻塞接口就会通知处理
什么是阻塞/非阻塞
阻塞,在电话预定座位的时候,你将自己挂起,等待...直到等到有座位的信息的时候才挂电话。
非阻塞,打电话预定座位,没有等店员回答你是否有结果,你就挂电话了,该干啥干啥。你也可以过几分钟过来催一下,看看店员有没有搞定。
什么是事件
点击,拖拽等都是事件
什么是事件驱动
有事我叫你,没事别烦我--当需要的时候才会被调用。
事件循环
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。
http概念进阶
上图中,主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部API,它们在"任务队列"中加入各种事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取"任务队列",依次执行那些事件所对应的回调函数。
Node.js的Event Loop
Node.js也是单线程的Event Loop,但是它的运行机制不同于浏览器环境。
http概念进阶
根据上图,Node.js的运行机制如下。

(1)V8引擎解析JavaScript脚本。

(2)解析后的代码,调用Node API。

(3)libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。

(4)V8引擎再将结果返回给用户。

除了setTimeout和setInterval这两个方法,Node.js还提供了另外两个与"任务队列"有关的方法:process.nextTick和setImmediate。它们可以帮助我们加深对"任务队列"的理解。

process.nextTick方法可以在当前"执行栈"的尾部----下一次Event Loop(主线程读取"任务队列")之前----触发回调函数。也就是说,它指定的任务总是发生在所有异步任务之前。setImmediate方法则是在当前"任务队列"的尾部添加事件,也就是说,它指定的任务总是在下一次Event Loop时执行,这与setTimeout(fn, 0)很像。请看下面的例子(via StackOverflow)。

process.nextTick(function A() {
  console.log(1);
  process.nextTick(function B(){console.log(2);});
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)
// 1
// 2
// TIMEOUT FIRED

上面代码中,由于process.nextTick方法指定的回调函数,总是在当前"执行栈"的尾部触发,所以不仅函数A比setTimeout指定的回调函数timeout先执行,而且函数B也比timeout先执行。这说明,如果有多个process.nextTick语句(不管它们是否嵌套),将全部在当前"执行栈"执行。

现在,再看setImmediate。

setImmediate(function A() {
  console.log(1);
  setImmediate(function B(){console.log(2);});
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0);

上面代码中,setImmediate与setTimeout(fn,0)各自添加了一个回调函数A和timeout,都是在下一次Event Loop触发。那么,哪个回调函数先执行呢?答案是不确定。运行结果可能是1--TIMEOUT FIRED--2,也可能是TIMEOUT FIRED--1--2。

令人困惑的是,Node.js文档中称,setImmediate指定的回调函数,总是排在setTimeout前面。实际上,这种情况只发生在递归调用的时候。

setImmediate(function (){
  setImmediate(function A() {
    console.log(1);
    setImmediate(function B(){console.log(2);});
  });

  setTimeout(function timeout() {
    console.log('TIMEOUT FIRED');
  }, 0);
});
// 1
// TIMEOUT FIRED
// 2

上面代码中,setImmediate和setTimeout被封装在一个setImmediate里面,它的运行结果总是1--TIMEOUT FIRED--2,这时函数A一定在timeout前面触发。至于2排在TIMEOUT FIRED的后面(即函数B在timeout后面触发),是因为setImmediate总是将事件注册到下一轮Event Loop,所以函数A和timeout是在同一轮Loop执行,而函数B在下一轮Loop执行。

我们由此得到了process.nextTick和setImmediate的一个重要区别:多个process.nextTick语句总是在当前"执行栈"一次执行完,多个setImmediate可能则需要多次loop才能执行完。事实上,这正是Node.js 10.0版添加setImmediate方法的原因,否则像下面这样的递归调用process.nextTick,将会没完没了,主线程根本不会去读取"事件队列"!

process.nextTick(function foo() {
  process.nextTick(foo);
});

事实上,现在要是你写出递归的process.nextTick,Node.js会抛出一个警告,要求你改成setImmediate。

另外,由于process.nextTick指定的回调函数是在本次"事件循环"触发,而setImmediate指定的是在下次"事件循环"触发,所以很显然,前者总是比后者发生得早,而且执行效率也高(因为不用检查"任务队列")。
Http缓存机制

http概念进阶

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
ROS回调函数传参
ROS编程过程中遇到不少需要给回调函数传递多个参数的情况,下面总结一下,传参的方法:一、回调函数仅含单个参数voidchatterCallback(conststd_msgs::String::ConstPtr&msg){ROS_INFO("Iheard:%s",msg
晴空闲云 晴空闲云
3年前
JavaScript中MutationObServer监听DOM元素详解
DOM的MutationObServer接口,可以在DOM被修改时异步执行回调函数,我的理解就是可以监听DOM修改。基本使用可以通过MutationObserver构造函数实例化,参数是一个回调函数。jsletobservernewMutationObserver(()console.log("change"));console.log(obs
菜园前端 菜园前端
2年前
什么是JavaScript异步模式
什么是异步模式?不会等待当前任务执行完毕,才会去执行下一个任务,这就是异步模式(Asynchronous)。开启异步后,就会跳过本任务,开始执行下一个任务,后续的逻辑一般会通过回调函数的方式定义。异步模式执行中,涉及到调用栈(Callstack)、消息队列
LinMeng LinMeng
4年前
js 的 forEach,map,filter,some,every,find(es6),reduce详解
forEach()定义和用法forEach()方法用于调用数组的每个元素,并将元素传递给回调函数注意:forEach()对于空数组是不会执行回调函数的。语法array.forEach(function(currentValue,index,arr),thisValue)参数function(currentValue,index,a
前端麦小子 前端麦小子
2年前
JavaScript异步的实现
你好,我是麦小子。编程领域的概念大多来自生活,异步也是如此。JS中的异步,有回调函数,期约,异步函数几种实现方式,一起探讨一下吧。
菜园前端 菜园前端
2年前
什么是回调函数?
原文链接:什么是回调函数?简单的来说,一个函数作为另外一个函数的参数,可以称为回调函数。这个理解其实不完全对,回调的意义根本没有体现出来,何为回调?也就是说一个函数你定义了,你没有马上的去调用它,而是交给了另外一个函数去调用,这才属于回调函数。缺点直接使用
Stella981 Stella981
3年前
JavaScript回调函数的高手指南
摘要:本文将会解释回调函数的概念,同时帮你区分两种回调:同步和异步。回调函数是每个前端程序员都应该知道的概念之一。回调可用于数组、计时器函数、promise、事件处理中。本文将会解释回调函数的概念,同时帮你区分两种回调:同步和异步。1.回调函数首先写一个向人打招呼的函数。只需要创建一个接受name参数的函数gree
Stella981 Stella981
3年前
ES6 Promise 对象扯谈
newPromise(/executor/function(resolve,reject){...});Promise的构造函数接收一个函数作为参数,函数里面传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。其实这里用“成功”和“失败”来描述并不准确,按照标准来
可莉 可莉
3年前
12306 抢票系列之只要搞定RAIL_DEVICEID的来源,从此抢票不再掉线(中)
直奔重点高楼大厦寻关键线索Js文件中关于网络请求最典型的就是异步回调,将原本简单的操作复杂化,非要你等我,我等他,他还等着他的她.最终直接结果就是整个请求流程反过来了,假设正常流程:是ABCDEF,那么异步请求很可能陷入这样的陷阱:F<E<D<C<B<A所以一层又一层的回调函数
Stella981 Stella981
3年前
ES6 Promise
Promisepromise是异步编程的一种解决方案1什么是异步?异步模式,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。"异步模式"非常重要。在浏
Stella981 Stella981
3年前
Spring 异步调用,多线程,一行代码实现
Spring异步调用,多线程概述快速入门异步回调异步异常处理自定义执行器1、概述在日常开发中,我们的逻辑都是同步调用,顺序