问题一:JS是同步的?
是的,JS是单线程,只能同步(排队)执行。
问题二:JS为什么需要异步
如果不存在异步, 代码只能自上而下执行,万一上一行代码解析时间很长,下面的代码就会被阻塞。对用户而言就意味着卡死, 导致很差的用户体验。
问题三:JS单线程如何实现异步
通过事件循环(event loop)实现异步
console.log(111)
setTimeout(()=>{
console.log(222)
},0)
console.log(333)
输出结果:111, 333,222
复制代码
setTimeout里的函数并没有立即执行,而是延迟了一段时间,满足一定条件后,才去执行的,这类代码,我们叫异步代码。
JS的执行机制是
- 首先判断js代码是同步还是异步,同步就进入主进程,异步就进入event table
- 异步任务在event table中注册函数,当满足触发条件后,被推入event queue
- 同步任务进入主线程后一直执行,直到主线程空闲时,才会去event queue中查看是否有可执行的异步任务,如果有就推入主进程中
以上三步循环执行,这就是event loop
总结:同步可以保证顺序一致,但是容易导致阻塞;异步可以解决阻塞问题,但是会改变顺序性,根据不同的需要去写你的代码。
1. JS异步函数的串行执行和并行执行
- 串行是指多个任务时,各个任务按顺序执行,完成一个之后才能进行下一个
- 并行指的是多个任务可以同时执行,异步是多个任务并行的前提条件
//串行执行arr中的函数
var series= function (arr, callback) {
var counter = 0;
var process = function () {
if (counter < arr.length) {
var fun = arr[counter++];
if (fun) fun(process);
} else {
if (callback) callback();
}
}
process();
}
复制代码
//并行执行arr中的函数
var parallel= function (arr,callback) {
var counter = arr.length;
var process = function () {
if (!--counter) {
if (callback) callback();
}
}
if (counter == 0) {
if (callback) callback();
} else {
arr.forEach(function (fun) {
if (fun) fun(process);
});
}
}
复制代码
2. 如何串行执行Promise
- 简单举例Promise.all的用法
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 2500)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222)
}, 3000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333)
}, 1000)
})
Promise.all([p1, p2, p3]).then(res => console.log('all', res)) // [111, 222, 333]
Promise.race([p1, p2, p3]).then(res => console.log('race', res)) // 333
复制代码
- Promise提供了Promise.all(),Promise.race(),Promise.allSettled()
- 如果并行运行可以用Promise.all来进行处理
- 如果要串行运行可以用数组的reduce来进行处理
const fn1 = function(arg) {
console.log('fn1', arg)
return Promise.resolve(111)
}
const fn2 = function(arg) {
console.log('fn2', arg)
// return Promise.reject(new Error('哎呦,出错了'))
return Promise.resolve(222)
}
const fn3 = function(arg) {
console.log('fn3', arg)
return Promise.resolve(333)
}
const serialPromise = function(promises) {
promises.reduce((prev, next) =>
prev.then(prevVal => next(prevVal)).catch(next()), Promise.resolve())
}
serialPromise([fn1, fn2, fn3])
// 如果有fn2执行reject,那么那个fn2会执行两次,
// 因为prev.catch等价于prev.then(undefined, onRejected)
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END