Day17 解决异步方法大汇总

106 阅读3分钟

每日一句

Life is about learning how to dance ine the rain.

释义:人生就是要学会在雨中跳舞。

前言

js是单线程的,就是要等前面的任务执行完才能执行后面的任务。如果任务一多,就会排队,依次执行任务队列,如果一个任务耗时太长就会拖垮整个程序,常见浏览器卡死无反应,无法继续。为了解决这个问题,js的执行模式分为同步和异步。

同步:就是等待前面的任务执行完之后才能执行后面的程序。

异步:前面的任务执行完,执行回调不执行后面的任务,后面的任务不用等待前面的任务是否执行完直接执行后面的任务。

同步和异步的区别:同步会阻塞后续代码的执行,异步不会阻塞后续代码的执行。

异步编程的方案

回调函数:setTimout/seInterval,ajax

ajax(url1, () => {
    ajax(url2, () => {
        ajax(url3, () => {
            ...
        })
    })
})

优点是简单,缺点也很明显就是回调地狱

事件监听

// fnA执行完,通过触发done事件,执行fnB.
function fnA() {
  setTimeout(() => {
     // jq方式
      fnA.trigger('done')
  },1000)
}

function fnB() {
    console.log('fnB dong.')
}
fnA.on('done', fnB)

优点是易于理解,可绑多个事件,每个事件可执行多个回调函数。

缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。阅读代码的时候,很难看出主流程。

promise/A+

let p = new Promise((resolve, reject) => { 
  if (true) {
    resolve('success')
  } else {
    reject('reject') 
  }
}) 
p.then( value => { 
  console.log(value) 
}, reason => { 
  console.log(reason)//reject 
})

promise不仅能够捕获错误,而且也很好地解决了回调地狱的问题。

缺点:比如无法取消 Promise,错误需要通过回调函数捕获。

async/wait

async function show() {
  const res = await say();
  console.log('end...', res)
}

function say(){
  return new Promise((resolve, reject) => {
     setTimeout(() => {
       console.log('ok...')
       resolve(1)
     },1000)
  })
}

async/await是基于Promise实现的。

async/await与Promise一样,是非阻塞的。

async/await使得异步代码看起来像同步代码

生成器Generators/yied

是ES6 提供的一种异步编程解决方案

function *foo(x) {
  let y = 2 * (yield (x + 1))
  let z = yield (y / 3)
  return (x + y + z)
}
let it = foo(1)
console.log(it.next())   // => {value: 2, done: false}
console.log(it.next(3)) // => {value: 2, done: false}
console.log(it.next(5)) // => {value: 12, done: true}
x=1, y=6,z=5

首先 Generator 函数调用和普通函数不同,它会返回一个迭代器

当执行第一次 next 时,传参会被忽略,并且函数暂停在 yield (x + 1) 处,所以返回 1 + 1 = 2

当执行第二次 next 时,传入的参数3就会被当作上一个yield表达式的返回值,如果你不传参,yield 永远返回 undefined。此时 let y = 2 * 3,所以第二个 yield 等于 6 / 3 = 2

当执行第三次 next 时,传入的参数5就会被当作上一个yield表达式的返回值,所以 z = 5, x = 1, y = 6,相加等于12

发布订阅

实现思路

  • 创建一个对象
  • 在该对象上创建一个缓存列表(调度中心)
  • on 方法用来把函数 fn 都加到缓存列表中(订阅者注册事件到调度中心)
  • emit 方法取到 arguments 里第一个当做 event,根据 event 值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)
  • off 方法可以根据 event 值取消订阅(取消订阅)
  • once 方法只监听一次,调用完毕后删除缓存函数(订阅一次)

观察者模式

观察者模式指的是一个对象(Subject)维持一系列依赖于它的对象(Observer),当有关状态发生变更时 Subject 对象则通知一系列 Observer 对象进行更新。

在观察者模式中,Subject 对象拥有添加、删除和通知一系列 Observer 的方法等等,而 Observer 对象拥有更新方法等等。