javascript之同步异步简述

javascript之同步异步简述

前言

最近准备把nodejs啃一啃,毕竟现在CTF的nodejs题还挺多的,并且nodejs也是必备知识,所以想学这nodejs搞个express或者koa玩玩,在学习过程中感觉与其他语言区别较大的也就是js中的同步和异步处理,并且感觉在js中,回调函数还是十分普遍的,因此要了解同步和异步的模式

正言


单线程

(1)单线程的概念

如果大家熟悉java,应该都知道,java是一门多线程语言,我们常常可以利用java的多线程处理各种各样的事,比如说文件上传,下载等,而JavaScript是否也可以支持多线程呢?

答案是否定的,JavaScript是一门单线程的语言,因此,JavaScript在同一个时间只能做一件事,单线程意味着,如果在同个时间有多个任务的话,这些任务就需要进行排队,前一个任务执行完,才会执行下一个任务,比如说下面这段代码

function fun1(){
  console.log(1);
}

function fun2(){
  console.log(2);
}

function fun3(){
  console.log(3);
}
fun1();
fun2();
fun3();
//1
//2
//3

会依次从上往下执行,但是如果fun1()中的代码执行的是读取文件或者ajax操作,文件的读取和数据的获取都需要一定时间,难道我们需要完全等到fun1()执行完才能继续执行fun2()?因此才有了异步的概念
(2)同步任务和异步任务
同步任务指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务,当我们打开网站时,网站的渲染过程,比如元素的渲染,其实就是一个同步任务

异步任务指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,当我们打开网站时,像图片的加载,音乐的加载,其实就是一个异步任务

function fun1(){
  console.log(1);
}

function fun2(){
  console.log(2);
}

function fun3(){
  console.log(3);
}

fun1();
setTimeout(()=>{
  fun2();
},0);

fun3();
//1
//3
//2

在输出中我们可以看到,由于setTimeout()是典型的异步处理,这里我们待会再讲,因此主线程中显然是会先完成同步任务,即执行完成fun1()和fun2()后,等到异步任务通知线程后在任务队列中调到了了主线程中,主线程才会最终调用

异步机制
上文提到了任务队列,因此这里先说明一下什么是任务队列?

在前面也介绍了,异步任务是不会进入主线程,而是会先进入任务队列,任务队列其实是一个先进先出的数据结构,也是一个事件队列,比如说文件读取操作,因为这是一个异步任务,因此该任务会被添加到任务队列中,等到IO完成后,就会在任务队列中添加一个事件,表示异步任务完成。当主线程处理完同步任务后,从消息队列取出一个事件消息,其对应异步任务(函数)入栈,执行回调函数,如果未绑定回调,这个消息会被丢弃,执行完任务后退栈

该机制实质上也就是事件循环的机制:

  • 1.宿主环境为JavaScript 创建线程时,会创建堆 (heap) 和栈 (stack) ,堆内存储 JavaScript 对象,栈内存储执行上下文;
  • 2.栈内执行上下文的同步任务按序执行,执行完即退栈,而当异步任务执行时,该异步任务进入等待状态(不入栈),同时通知线程:当触发该事件时(或该异步操作响应返回时),需向消息队列插入一个事件消息;
  • 3.当栈内同步任务执行完毕后,线程从消息队列取出一个事件消息,其对应异步任务(函数)入栈,执行回调函数,如果未绑定回调,这个消息会被丢弃,执行完任务后退栈;
  • 4.当线程空闲(即执行栈清空)时继续拉取消息队列下一轮消息

这也就是异步处理的大致原理,因为前段实在是用到很多异步,因此回调函数确实出现频率很大,下面提及异步编程的实现:

  • 回调函数
    这也是为什么回调函数如此频繁的原因。举个具体的例子来说明回调函数的异步体现:
function getData(){
   setTimeout(()=>{
       var name = 'crispr';
       return name;
   },1000);
} 
console.log(getData());
//undefined

本来是想得到返回的字符串,但是却返回了undefined,原因就是因为setTimeout()是异步的,当js代码执行到这里的时候,不会等待异步请求完毕,就直接return了,所以值就一直是undefined,因此如果想实现我们的目的有两种方法,一种是在加入回调函数进行返回

function getData(callback){
   setTimeout(()=>{
       var name = 'zhangsan';
       callback(name);
   },1000);
} 
getData((name)=>{
   console.log(name);

这样callback就相当于一个console.log,最终能够输出crsipr,还有一种方法也是异步编程实现的重要依据

  • Promise对象
    在这里插入图片描述
    在这里插入图片描述
    当我们使用Promise来达到我们之前的目的时,应该这样使用
function getData(resolve,reject){
    setTimeout(()=>{
        var name = 'crispr';
        resolve(name);
    },1000)
}
var p = new Promise(getData);
p.then((name)=>{
    console.log('your name is ' + name);
})
//crispr
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值