1. 同步与异步
1.1 同步行为synchronous
内存中顺序执行的处理器指令
1.1.1 特点
- 每条指令都会严格按照它们出现的顺序执行
- 每条指令执行后能立即获得存储在系统本地的信息
- 容易分析程序在执行到代码任意位置时的状态
1.1.2 例子
let x = 3;
x = x + 4;
等到最后一条指令执行完毕,存储在x的值立即可以使用
let girlName = "裘千尺"
function hr() {
girlName = "黄蓉"
console.log(`我是${
girlName}`);
}
function gj() {
console.log(`${
girlName}你好,我是郭靖,认识一下吧`);
}
hr()
gj()
//=>我是黄蓉
//=>黄蓉你好,我是郭靖,认识一下吧
1.2 异步行为asynchronous
类似于系统中断,即当前进程外部的实体可以触发代码执行
1.2.1 必要性
同步执行的代码必须要强制等待一个长时间的操作(比如向服务器发送请求并等待相应)
需要等待但是又不能阻塞程序的时候需要使用异步
1.2.2 特点
- 异步代码不容易推断
- 异步指令会生成一个入队执行的中断,什么时候触发中断,对JavaScript来说是个黑盒,无法预知
- 当前线程所有同步代码执行结束,回调才有机会出列被执行
1.2.3 例子
let x = 3;
setTimeout(() => x = x + 4, 1000);
线程不知道x
值何时会改变,这取决于回调何时从消息队列出列并执行
let girlName = "裘千尺"
function hr() {
setTimeout(() => {
girlName = "黄蓉"
console.log('我是黄蓉');
}, 0);
}
function gj() {
console.log(`${
girlName}你好,我是郭靖,认识一下吧`);
}
hr()
gj()
//=>裘千尺你好,我是郭靖,认识一下吧
//=>我是黄蓉
1.3 异步运行机制
- 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)
- 主线程之外,还存在一个任务队列(task queue)。只要异步任务有了运行结果,就在任务队列之中放置一个事件
- 一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行
- 主线程不断重复上面的第三步
1.4 为什么要异步编程
为了让后续代码能够使用 x
,异步执行的函数需要在更新x的值后通知其他代码
如果程序不需要这个值,那么就继续执行,不必等待这个结果
所以要设计一个能够知道 x
什么时候可以读取的系统
来看一个例子
<button onclick="updateSync()"