异步函数详情

异步函数

1. 什么是线程

一个线程就是一个基本的处理过程,程序用它来完成任务。每个线程一次只能执行一个任务,其他任务都要在后面排队等待;

现在的计算机大多都有多个内核,因此可以同时执行多个任务。支持多线程的编程语言可以使用功能计算机的多个内核,同时完成多个任务;

进程是资源分配的最小单位,线程是CPU调度的最小单位

浏览器每个页面下有5个线程:

  1. 渲染线程(画页面);
  2. js引擎线程(执行脚本代码);
  3. 遇见setTimeout promise之类的异步, 新起一个线程去处理其中的异步任务;
  4. 遇见事件处理函数, 新起一个一个线程去执行事件处理函数中的代码;
  5. 遇见ajax新起一个线程专门去做请求,请求完成把结果丢到事件队列中;
2. JavaScript是单线程

所谓的单线程是指:JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完毕后才能执行下一个,它会[阻塞]其他任务。

单线程模式:
优点: 实现起来比较简单,执行环境相对单纯;
缺点: 只要有一个任务耗时很长,后面的任务都必须排队跟着,会拖延整个程序的执行;

JavaScript运行时,除了一个正在运行的主线程,JS引擎还提供一个任务队列,里面是各种需要当前程序处理的异步任务。(实际上,根据异步任务的类型,存在多个任务队列)

3.什么是异步?

异步模式可以一起执行多个任务;

简单来说就是: 当你向服务器请求数据, 等待服务器返回数据需要30s, 这时有两种情况:
1. 等待服务器返回数据,这期间不执行后续代码,等服务器返回数据后, 再执行后面的代码;
2. 充分利用这等待的30s,跳过这一步去执行其他的代码,等服务器返回数据了,在回来执行返回数据后的代码;
这第一种情况称为"同步", 而第二种情况就是"异步";

同步任务和异步任务

代码执行: 先执行同步, 再执行异步。

同步任务: 那些没有被引擎挂起、在主线程排队执行的任务。只有前一个任务执行完毕,才能执行后一个任务。

异步任务: 那些被引擎放在一边、不进入主线程,而进入任务队列的任务。只有引擎认为某个异步任务可以执行了(比如Ajax从服务器得到了数据),该任务(采用回调函数的形式)才会进入主线程执行。排在异步任务后面的代码,不用等待异步任务结束, 而是会马上执行,也就是说异步任务不具有"堵塞"效应。

那么JavaScript引擎又怎么知道异步任务有没有结果, 能不能进入主线程呢?答案就是: 引擎在不停的检查,一遍又一遍,只要同步任务执行完毕了,引擎就会去检查那些被挂起来的异步任务,是不是可以进入主线程了。这种循环检查的机制叫做事件循环

4. 哪些情况属于异步?

JS中常见的异步调用:
定时器;
ajax;
事件函数;

  1. 回调函数
function eat () {
  console.log('好的,我开动咯');
}
function cooking(cb) {
  console.log('妈妈认真做饭');
  setTimeout(function () {
    console.log('小明快过来,开饭啦')
    cb();
  },1000);
}
function read () {
console.log('小明假装正在读书');
}
cooking(eat);
read();
/*
执行顺序:
妈妈认真做饭;
小明假装正在读书;
小明快过来,开饭啦;
好的,我开动咯;
*/ 
  1. 事件监听
function eat() {
  console.log('妈妈敲门啦,该去吃饭啦');
}
function cooking () {
  console.log('妈妈认真做饭');
  setTimeout(function () {
  console.log('小明,出来吃饭啦')
  bus.$emit('done');
  },3000);
}
function read() {
  console.log('小明又假装在读书');
  bus.$son('done', eat);
}
cooking();
read();
/*
执行顺序:
妈妈认真做饭;
小明又在假装读书;
小明,出来吃饭啦;
妈妈敲门啦,该去吃饭啦;
*/
  1. 订阅与发布
function eat () {
  console.log('爸爸叫我去吃饭啦');
}
function cooking () {
  console.log('妈妈认真做饭');
  setTimeout(function () {
    console.log('孩子他爸,叫小明出来吃饭');
  }, 3000);
}
function read () {
  console.log('小明依旧假装正在读书');
  Dad.subscribe('done', eat);
}
cooking();
read();
/*
执行顺序: 
妈妈认真做饭;
小明依旧正在假装读书;
孩子他爸,叫小明出来吃饭;
爸爸叫我去吃饭啦;
*/
  1. promise

案例一:

function read () {
  console.log('小明认真读书');
}
function eat () {
  return new Promise((resolve,reject) => {
    console.log('好嘞,吃饭咯');
    setTimeout(() => {
      resolve('饭吃饱啦');
    }, 1000)
  })
}
function wash () {
  return new Promise((resolve, reject) => {
    console.log('唉, 又要洗碗');
    setTimeout(() => {
      resolve('碗洗完啦');
    }, 1000)
  })
}
function mop () {
  return new Promise((resolve, reject) => {
    console.log('唉, 又要拖地');
    setTimeout(() => {
      resolve('地拖完啦');
    }, 1000)
  })
}
const cooking = new Promise((resolve, reject) => {
  /* 这一步属于同步任务, 所以接下来执行另外一个同步任务: read(); */ 
  console.log('妈妈认真做饭'); 
  /* 同步任务执行完毕后, 开始执行异步任务; */
  setTimeout(() => {
    resolve('小明快过来,开饭啦');
  }, 3000)
})
/* 前一个then执行完毕后, 才能执行下一个then */
cooking.then(msg => {
  console.log(msg);
  return eat();
}).then(msg => {
  console.log(msg);
  return wash();
}).then(msg => {
   console.log(msg);
   return mop();
}).then(msg => {
   console.log(msg);
   console.log('终于结束啦, 出去玩咯');
})
read();
/*
执行顺序:
妈妈认真做饭;
小明认真读书;
小明快过来, 开饭啦;
好嘞,吃饭咯;
饭吃饱啦;
唉,又要洗碗;
碗洗完啦;
唉, 又要拖地;
地拖完啦;
终于结束啦, 出去玩咯;
*/

案例二:

console.log(1)

let promise = new Promise((resolve, reject) => {
  //内部执行异步操作
  console.log(2) // 这一步是同步任务
  resolve(123)
  //setTimeout(() => {}, 1000)
})

promise.then(data => {
  console.log(4)
  console.log('data', data) // 这里的data代表成功时执行的函数(resolve)中的结果数据;
})

// setTimeout第二个参数定义延迟的时间,如果定义的时间小于4ms,浏览器会默认按照4ms执行;
// setTimeout第三个参数,都会被传递给第一个函数参数;

setTimeout(
  arg => {
    console.log(5)
    console.log(args)
  },
  0,
  {a: 1, b: 2}
)

console.log(6)

/*
console.log 打印结果顺序:
1
2
6
4
123
5
*/
  1. 定时器
  2. ajax
  3. setInterval

宏任务: setTimeout setInterval, 异步任务中的微任务先被执行,宏任务后执行;
微任务: promise mut

注: 里面有借鉴前辈的成果

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值