js执行顺序+同步异步

JavaScript015

js执行顺序+同步异步,第1张

按照js同步执行的顺序,函数调用会首先执行for循环,循环5次开启了5个延迟器,延时器内部的回调函数将会异步执行,会在延时1s后进入消息队列等待执行。循环了5次,所以此时i的值为5,然后同步执行console.log打印5,第一次同步执行结束,然后开始执行消息队列的异步任务,打印5个5,中间的undefined是函数调用无返回值返回的。

执行顺序和第一题相同,不同的是延时器被包裹在了一个立即执行函数内容,并把每一次循环的i作为参数传入,此时循环内部的函数形成了一个私有作用域,每一次的i变量被独立保存了起来,因此每一次循环的i的值都会被打印出来。

延时器内部回调函数是异步函数,将在延时结束后,进入消息队列等待执行,因此同步的console.log("CCCC")最优先执行,然后延时0ms的延时器的回调先进入消息队列,1000ms后第一个延时器的回调再进入消息队列等待执行,因此先执行0ms的回调打印DDDD,再执行1000ms的回调打印BBBB。

这里与上一题不同的是中间多了一个执行3s的同步while循环,因此执行顺序是这样的:

第一个延时器延时1s后内部异步回调函数进入消息队列等待执行,

等待while循环3s后打印"CCCC",

循环结束后第一个延时器内部的回调已经进入消息队列第一个执行位置等待执行。

第二个延时器延时0s后内部异步回调函数进入消息队列等待执行,延时结束后排到第一个延时器的回调函数后面,

因此异步队里内部先打印"BBBB",再打印"DDDD"

settimeout是异步方法,会排到消息队列去执行,也就是执行异步方法的队列称为消息队列。

js主要是多线程执行的,而执行非异步方法的部分称为主线程,消息队列其实也是一个线程,称为副线程,而主线程执行完毕才会执行副线程。

副线程(消息队列)并非只有一个,为了执行效率和顺序分为 宏任务线程 微任务线程 ,只有微任务进程执行完才会执行宏任务进程

其中23456就是事件轮询

Generator函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权

该函数返回一个状态机,必须要靠状态机.next()才能执行

执行过程只需要记住一句话

执行到yield就暂停,返回yield后面值,第一次执行参数无用,再次执行参数赋给yield前面的表达式。

async、await是Generator函数的语法糖,原理是通过Generator函数加自动执行器来实现的,这就使得async、await跟普通函数一样了,不用再一直next执行了

所以本质上async await是generator与promise结合的语法糖

三者调用请求的对比案例:

promise

generator

async

MQ全称为Message

Queue,

消息队列(MQ)是一种应用程

序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们>。消

息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过

队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。其中较为成熟的MQ产品有IBM

WEBSPHERE

MQ。

以上介绍仍旧来自百度百科.

消息队列产品对比

目前比较流行的MQ有2种,ActiveMQ

以及

RabbitMQ

,

RabbitMQ性能号称能够达到每秒10000,而REDIS官方的压力测试值在7-8万之间,而且是去掉了网络IO操作,真实情况我估计在每秒2-3

万的并发操作,但这个数目对于一般的应用应该足够了.

Redis如何支持消息队列?

在新版本的redis

v2.6以上以及以上版本开始支持

subscribe

以及

publish

操作,

subscribe订阅一个频道,publish可以像频道广播消息.

这个机制最老的应用应该是算是聊天室了.

Sub/Pub

模式固然很好用,但是同样有一个问题,就是如果有多个人订阅了同一频道,而这个频道的数据只能被一个接收方处理,不能够重复处理,这时该怎么办?

解决方法有2种,

1.

publish

将数据写入到一个list

or

sorted

list

队列,写完成后开始给终端广播消息,告诉大家,有新的数据等待处理,这个时候,谁能pop到数据,就是谁处理,这个操作是原子性的,也就是说不会被重复处理.

2.

使用阻塞模式,

redis提供了blpop

brpop这种操作,也就是一直阻塞一个队列,直到有数据来.

这种模式保证了数据的原子性,而且使应用程序可以支持分布式多台机器部署.

Sub/Pub模式

(sub.js):

var

redis

=

require("redis")

var

client

=

redis.createClient(6379,

‘127.0.0.1‘,

{connect_timeout:

1})

//订阅一个频道

var

sub

=

function(c)

{

var

c

=

c

||

‘roban:test:channel‘

client.subscribe(c,function(e){

console.log(‘starting

subscribe

channel:‘+c)

})

}

//订阅一个频道

sub()

//处理错误,如果出现错误,或者服务器断开了链接,等待恢复时,继续订阅这个频道

client.on(‘error‘,

function(error)

{

console.log(error)

sub()

})

//订阅处理函数

client.on(‘message‘,function(err,response){

console.log(response)

})

打开redis命令行,输入以下命令:

publish

roban:test:channel

hello

发布这条信息后,sub端会输出以下信息:

Robans-Pro:node

robanlee$

node

demo.js

starting

subscribe

channel:roban:test:channel

hello