为什么需要异步
要回答异步编程方案的原理,就必须要回到异步本身的概念和背后实现的原理上。
我们为什么会需要异步?
先说说为什么需要。因为我们,不想等。比如说我们当前正在进行【任务一 IO任务】:12345,分为IO请求12,针对请求成功后得到的资源的行为345.如果要同步(顺序)执行12345,当执行12的时候,IO设备忙碌,但CPU空闲。语言的设计者意识到此时完全可以将代码挂起,去执行后面的任务二。等IO请求完成之后,再来继续完成IO任务中的345。
(以上这段整理自:js异步编程与async/await替代糖)
这一段话,其实相当不清楚。
IO请求为什么可以和CPU执行并行?
将代码挂起是什么意思,挂在哪里,挂起是指暂停吗,还是等待呢,等待的话等到什么时候呢?
怎么知道IO请求完成了?
javascript引擎怎么知道345是什么呢,它之前一直在执行任务二、任务三,怎么突然跳到345的呢?
这就要用【浏览器又是如何实现异步的】来回答了。
异步是一种结果,我们要做的是让异步发生。
怎么让异步发生,【event-loop】让异步发生。
Event Loop的理解,请看阮一峰的博文:JavaScript 运行机制详解:再谈Event Loop 下面是一些摘要:
(转引自Philip Roberts的演讲《Help, I’m stuck in an event-loop》) WebAPIs:浏览器提供的一套操作浏览器功能和页面元素的API。 上图中,主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部API,它们在”任务队列”中加入各种事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取”任务队列”,依次执行那些事件所对应的回调函数。
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。 (2)栈中的代码调用各种Web API,执行异步任务。只要异步任务有了运行结果,就在”任务队列”(callback queue)之中放置一个事件。 (3)一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,看看里面有哪些事件。那些事件所对应的回调函数,结束等待状态,进入执行栈,开始执行。 (4)主线程不断重复上面的第三步。
现在来回答刚刚的四个问题。
- IO请求为什么可以和CPU执行并行?
这是浏览器的设计,浏览器一共有四个线程:javascript引擎线程、负责界面渲染的DOM线程、负责HTTP请求的ajax线程、负责事件触发的setTimeout线程。我的理解是,IO请求由负责HTTP请求的ajax线程负责,CPU执行由javascript引擎线程负责,浏览器有多个线程,所以可以并行。
- 将代码挂起是什么意思,挂在哪里,挂起是指暂停吗,还是等待呢,等待的话等到什么时候呢?
我的理解:挂起就是【javascript引擎线程】把这个【IO任务】的执行权交给【负责HTTP请求的ajax线程】。【负责HTTP请求的ajax线程】收到请求结果之后,在“任务队列task queue”中放置一个onLoad事件。
- 怎么知道IO请求完成了?
主线程(即【javascript引擎线程】)执行完“执行栈”里的所有同步任务后去读取“任务队列”,看到里面有onLoad事件,就知道IO请求已完成。
- javascript引擎怎么知道345是什么呢,它之前一直在执行任务二、任务三,怎么突然跳到345的呢?
回调函数(只要指定过回调函数,这些事件发生时就会进入“任务队列”,等待主线程读取)。
异步方案的发展(出现问题->解决问题)
异步方案摘自《JavaScript高级程序设计》和《JavaScript忍者秘籍》,并加入了一些自己的理解。
promise的api介绍
const promise = new Promise(function(resolve, reject) {// ... some codeif (/* 异步操作成功 */){resolve(value);} else {reject(error);}});
} });
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
async/await和promise/generator的联系
功能相同,效果不同。
Async和await实现连续异步:
(转引自Philip Roberts的演讲
