异步的理解
宿主环境:浏览器环境/Node环境
我们写了一段JS代码时,浏览器或Node环境传递给JS引擎,并且要求他们去执行
所以JS引擎会常驻在内存中,等待宿主环境(我们)把JS代码传递给他去执行
ES3及其之前JS本身没有能力执行异步代码,宿主环境将代码传递给JS引擎,JS引擎就顺次执行下去,这个任务是宿主发起的
ES5之后,JS引入了Promise,不需要宿主环境安排,JS引擎本身也就可以发起任务
宿主发起的任务称之为:宏任务
JS引擎发起的任务称之为:微任务
JS引擎等待宿主环境分配宏任务,在操作系统中,等待的行为都是一个事件循环,所以在Node术语这一部分称之为:事件循环
Promise
function sleep (sec) {
return new Promise((resolve,reject)=>{setTimeout(resolve,sec)})
};
sleep(2000).then(()=>{console.log('hello')})
async sleep (sec) {
console.log('hello');
await sleep(3000);
console.log('world');
}
实现一个红绿灯,把一个圆形div按照绿色3秒,黄色1秒,红色2秒循环改变背景色
<style>
#test {
border: 20px;
width: 100px;
height: 100px;
background-color: #ccc;
border-radius: 50%;
}
</style>
<body>
<div id="test"></div>
<script>
const light = document.getElementById( 'test' );
console.log( light );
function sleep( sec ) {
return new Promise( ( resolve, reject ) => {
setTimeout( resolve, sec );
} )
};
async function shineLight() {
while ( 1 )
{
light.style.backgroundColor = 'green';
await sleep( 3000 );
light.style.backgroundColor = 'yellow';
await sleep( 1000 );
light.style.backgroundColor = 'red';
await sleep( 2000 );
}
}
shineLight();
</script>
</body>
generator
参考:generator
function* foo(x) {
let y = 2 * (yield (x + 1));
let z = yield (y / 3);
return (x + y + z);
};
let it = foo(5);
console.log('it', it);
console.log(it.next()); //{value: 6, done: false}
console.log(it.next(12));
console.log(it.next(13));
- generator函数:
- 交出函数的执行权(暂停执行)多线程协同执行
- generator函数不是普通函数,
- 是可以暂停执行的函数 ;
- 异步操作需要暂停的地方都通过yield标注。
- 调用函数并不执行,也不返回函数执行结果。
- 不返回结果,而是返回一个指向内部状态的指针对象(遍历器对象)。
- 调用next方法,内部指针从函数头部或上一次停下来的地方开始执行, 直到遇到下一个yield或return。
- generator函数是分段执行的,yield是暂吋执行的标志,next可以恢复执行。
- generator函数数据交换:
- 第一个next方法,返回表达式x+2的值;
- 第二个next方法有参数2,作为上个阶段异步任务的返回结果,被函数体内的变量y接收;
- next的参数可以让generator函数在运行之后,还能注入值,
- next方法参数表示上一个yield表达式的返回值,所以在第一次使用next传递参数是无效的。
async
async function async1() {
console.log('async1 start')
await async2() //等async2执行完毕,会阻塞后面的代码,跳出async函数,执行其他代码
console.log('async1 end') //放入到Promise.then中的代码
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1')
resolve();
}).then(function () {
console.log('promise2')
})
console.log('script end')
/*
同:‘script start’ ‘async1 start’ ‘async2’ promise1 ‘script end’
宏:‘setTimeout’
微:‘async1 end’ ‘promise2’
*/
-
异步的终极解决方案
-
就是generator加上Promise的语法糖
-
封装了generator的执行器和返回一个Promise
-
- 返回的是一个Promise
- await后面【表达式】的可以是一个Promise也可以是一个值,但是最终都转换成resolved的Promise;
- await 下面的代码相当于Promise的then里的代码
-
区别generator:内置了执行器,而且语义上更好理解,将异步函数以普通同步函数的方式书写。
-
generator需要next函数触发执行
-
EventLoop
- 浏览器的EventLoop
- 执行同步代码,
- 同步代码执行完后,执行栈为空,检查是否有异步代码需要执行,
- 执行所有微任务,
- 然后下一轮EventLoop,执行宏任务中的异步代码。
- Node中的EventLoop