Skip to content
On this page

异步编程

并发和并行

知乎上的高赞回复

你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。

你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。

你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。

并发的关键是你有处理多个任务的能力,不一定要同时。

并行的关键是你有同时处理多个任务的能力。

所以我认为它们最关键的点就是:是否是『同时』。

并发是宏观概念,指的是具备任务切换的能力。

并行是微观概念,指的是具备处理多任务的能力。因此单CPU不能实现并行。

回调函数

缺点

  • 容易造成回调地域,也就是嵌套函数,存在耦合性,不利于维护
  • 难以处理错误,也无法用try{...}catch(err){...}捕捉错误
  • 不能直接return

Cenerator

  • 定义
    • function*返回一个Generator对象
  • 作用
    • 控制函数的执行
  • 执行过程
    • 调用next()方法时,函数执行到出现yield处暂停执行
      • next()方法返回一个对象,包含两个属性:valuedonevalue 属性表示本次 yield 表达式的返回值done 表示生成器后续是否还有 yield 语句,即生成器函数是否已经执行完毕并返回
    • 如果函数中用的是yield*,则表示将执行权移交给另一个生成器函数(当前生成器暂停执行)
    • 如果向next()传入参数,会传给上一条执行的 yield语句左边的变量,第一个next()传参无效
    • 如果函数中显式return,导致生成器立即变为完成状态,如果return一个值,则作为next()返回的value
js
// MDN上的例子
function *createIterator() {
    let first = yield 1;
    let second = yield first + 2; // 4 + 2
                                  // first =4 是next(4)将参数赋给上一条的
    yield second + 3;             // 5 + 3
}

let iterator = createIterator();

console.log(iterator.next());    // "{ value: 1, done: false }"
console.log(iterator.next(4));   // "{ value: 6, done: false }"
console.log(iterator.next(5));   // "{ value: 8, done: false }"
console.log(iterator.next());    // "{ value: undefined, done: true }"

Promise

  • 一种异步编程的解决方案
  • 传统的解决方案——回调函数和事件
  • Promise对象的特点
    1. 对象的状态不受外部影响,内部抛出的错误也不会影响到外部
    2. 支持链式调用
    3. 一旦状态改变,就不会再变
      • pending->fulfilled
      • pending->rejected
    4. 这两种状态一发生,我们就称为resolved,如果状态已经改变了,再去添加回调函数,那么也会拿到结果
      • 与事件的特点不同。事件的特点是,如果你错过了它,再去监听,是得不到结果的
    5. 无法取消Promise,一旦新建它就会立即执行,无法中途取消(缺点)
    6. 当处于pending状态时,无法得知目前进展到哪一个阶段(缺点)

详见Promise

async和await

async就是将函数的返回值使用Promise.resolve()包裹一层, 和 then 中处理返回值一样,并且 await 只能配套 async 使用

await就是generatorPromise的语法糖,并且内部实现了自动执行generator

  • 特点
    • 异步终极解决方案
  • 优点
    • 处理then的调用链
    • 代码逻辑更清晰,书写更像同步代码
  • 缺点
    • 如果多个异步代码不存在依赖关系,使用了 await 会导致性能上的降低,可以使用Promise.all()的方式

TODO async和await的实现

定时器函数

常⻅的定时器函数有 setTimeoutsetIntervalrequestAnimationFrame

如果前面的代码 影响了性能,就会导致 setTimeout 不会按期执行。

通常来说不建议使用 setInterval

  • 它和 setTimeout 一 样,不能保证在预期的时间执行任务
  • 它存在执行累积的问题,如果定时器执行过程中出现了耗时操作, 多个回调函数会在耗时操作结束以后同时执行,这样可能就会带来性能上的问题。

requestAnimationFrame 自带函数节流功能,基本可以保证在 16.6 毫秒内只执行一次(不掉帧的情况下),并且该函数的延时效果是精确的,没有其他定时器时间不准的问题

TODO 可以通过requestAnimationFrame实现 setTimeoutsetInterval

MIT Licensed | Copyright © 2021 - 2022