事件循环我到现在都没有弄清楚,不过慢慢地有一点儿眉目了.能够根据代码判断出执行结果了.后面再慢慢消化吧.
console.log('1');
setTimeout(function() {
console.log('2');
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5');
})
}, 0);
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8');
});
new Promise(function(resolve) {
console.log('13');
resolve();
}).then(function() {
console.log('14');
});
setTimeout(function() {
console.log('9');
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12');
});
}, 0);
以上代码的运行结果是 1, 7, 13, 8, 14, 2, 4, 5, 9, 11, 12
所以根据运行结果去分析,console直接运行,promise也是直接运行,promise后面的then会放在某一个任务队列(应该是微任务),setTimeout是宏任务,轮到某一宏任务执行时,必然会把该宏任务中的所有任务执行完成才会执行下个宏任务.队列是先进先出所以在同一类队列中,先放入的先执行.
另外一道题:
console.log('1');
setTimeout(() => {
console.log('2');
Promise.resolve().then(() => {
console.log('3');
})
new Promise((resolve) => {
console.log('4');
resolve();
}).then(() => {
console.log('5')
})
})
Promise.reject().then(() => {
console.log('13');
}, () => {
console.log('12');
})
new Promise((resolve) => {
console.log('7');
resolve();
}).then(() => {
console.log('8')
})
setTimeout(() => {
console.log('9');
Promise.resolve().then(() => {
console.log('10');
})
new Promise((resolve) => {
console.log('11');
resolve();
}).then(() => {
console.log('12')
})
})
答案:1, 7, 12, 8, 2 ,4 ,3 , 5 ,9 ,11 ,10, 12
从这题可以总结: 每一个setTimeout模块儿完成后才会执行其他模块儿
以下两道题如果不仔细很容易弄错
var promise1 = () => (
new Promise( resolve => {
console.log(1);
var promise2 = new Promise( resolve => {
console.log(2);
setTimeout( ()=>{
console.log(3);
resolve();
},0);
});
resolve()
promise2().then( ()=> {
console.log(4);
});
})
);
promise1().then( () => {
console.log(5);
});
console.log(6);
答案: 1, 2, 6, 5, 3
var promise1 = () => (
new Promise( resolve => {
console.log(1);
var promise2 = () => (
new Promise( resolve => {
console.log(2);
setTimeout( ()=>{
console.log(3);
resolve();//promise2后面的then方法得在执行这个宏任务时才放到微任务中;若这行代码和上一行代码交换位置输出结果一样,原因:打印3立即执行而打印4放在了微任务队列
},0);
})
);
resolve()
promise2().then( ()=> {
console.log(4);
});
})
);
promise1().then( () => {
console.log(5);
});
console.log(6);
答案: 1, 2, 6, 5, 3, 4
以上两道题的主要区别在于promise2是一个函数还是一个promise对象.是一个对象时promise2()就会出错,所以紧随其后的then不会执行.
为什么5在 3和4的前面?调用promise1()的时候其后的then方法就放在微任务队列里面了吗?接着与下面这一题进行对比:
var promise1 = () => (
new Promise( resolve => {
console.log(1);
var promise2 = () => (
new Promise( resolve => {
console.log(2);
resolve();
})
);
resolve()
promise2().then( ()=> {
console.log(4);
});
})
);
promise1().then( () => {
console.log(5);
});
console.log(6);
答案: 1, 2, 6 , 4, 5
如果按照假设: 调用promise1()后,它的then即刻放入微任务队列,那这题的答案就不是这样的,所以假设不成立. 应该是创建的promise对象完成(无论是是rejected还是resolved)后其后的then方法才放入微任务队列中. Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。通过下面这题就能得出答案: resolve()调用的位置是影响5被打印的时机的关键.
var promise1 = () => (
new Promise( resolve => {
console.log(1);
var promise2 = () => (
new Promise( resolve => {
console.log(2);
setTimeout( ()=>{
console.log(3);
},0);
resolve()
})
);
resolve();//此时promise1后面的then方法就放入到微任务队列了
promise2().then( ()=> {
console.log(4);
});
})
);
promise1().then( () => {
console.log(5);
});
console.log(6);
答案: 1, 2, 6, 4, 5, 3.
有async/await的事件循环:
console.log('script start');
setTimeout(() => {
console.log('北歌');
}, 1 * 2000);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
async function foo() {
await bar()
console.log('async1 end')
}
foo()
function bar() {
console.log('async2 end')
}
async function boo() {
await baz()
console.log('async3 end')
}
boo()
function baz() {
console.log('async4 end')
}
console.log('script end');
运行得到的结果: script start async2 end async4 end script end promise1 async1 end async3 end promise2 北歌
对async/await不太懂的,可以先看下面这个例子
async function foo() {
await bar();
await zar();
console.log('await')
}
function bar() {
console.log('bar')
}
function zar() {
console.log('zar')
}
console.log('1')
foo();
console.log('2')
运行结果: 1 bar 2 zar await
注意:await后的是同步任务还是异步任务
async f1(testuid: string) { await f1();//f1为同步任务 await console.log('llll') }
// 执行完f1时再打印'llll',如果f1是异步则f1依然会后执行
从这里例子中可以得出: 只有第一await 后面的函数会被立刻执行,其他的都会放入微任务队列中(与promise.then里面的执行代码处于同一个队列),等待异步函数foo()后面的所有同步任务执行完毕才会去执行微任务队列中的任务.
async/await 中当出现错误时的执行顺序
console.log('script start');
setTimeout(() => {
console.log('北歌');
}, 1 * 2000);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
async function foo() {
await bar()
console.log('async1 end')
}
foo()
function bar() {
console.log('async2 end')
}
async function errorFunc () {
try {
await Promise.reject('error')
} catch(e) {
console.log(e)
}
console.log('async1');
return Promise.resolve('async1 success')
}
errorFunc().then(res =>
console.log(res)
)
console.log('script end');
其执行结果: script start async2 end script end promise1 async1 end promise2 error async1 async1 success 北歌
与前面一个例子对比能够总结到: 到async /await 中出现错误时,整个代码块涉及到的内容都会放在微任务队列的后面(等其他微任务执行完以后才执行).当然,还是要比宏任务先执行.即使把foo()放在 errorFunc()函数的后面,它也在在所有的微任务执行完后才会执行.
此处出错的原因是 代码Promise.reject('error')会报错,而正确书写的形式如下:
Promise.reject('error').then(()=>{}, ()=> {console.log('reject')});
返回的promise的状态是rejected,所以会输出'reject'
async/await更加全面的例子
输出结果: '1', bar, '2', 1, zar, 3, await
可以得出这个例子的具体执行过程是:
同步代码直接运行('1');异步函数foo()先执行await bar,输出'bar'; 现在只将await zar()放入微任务队列中(下面的同步代码并没有放入微任务队列); 运行同步代码,输出'2'; promise立即执行,输出1; 因为成功所以将console.log(3)放入微任务队列;第一次轮询结束,进入下一个轮询; 微任务的依次执行,输出'zar';将console.log('await')放入微任务队列; 输出3; 输出await;微任务队列也执行完毕.宏任务队列为空;整个执行结束;
await bar()执行完将 await zar()放入微任务队列; await zar()执行完才会将console.log('await')这个同步代码放入微任务队列. 而不是await bar()执行完后将后面的所有一次性放入微任务队列
Promise.resolve()是微任务
setTimeout(
()=> console.log(4)
, 100);Promise.resolve()
.then(()=> console.log('1'))
.then(()=> console.log('2'));
console.log('3');
输出结果为: 3, 1, 2, 4. 可见Promise.resolve()是微任务
文中如有错误,欢迎指正.相互学习!