JS同步异步笔记

问题一: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
喜欢就支持一下吧
点赞0 分享