JavaScript异步

By :  司嘉年(moke)

JavaScript是单线程?

  • JS引擎中负责解释和执行JS代码的线程只有一个(主)
  • AJAX、处理DOM、定时器、读写......(工作线程)
  • 对于耗时或者时间不确定的操作,使用异步
  • html5 web worker 多线程

异步执行机制

  1. 所有同步任务都在主线程执行,形成执行栈
  2. “任务队列”,异步任务的结果存放
  3. 同步任务执行完毕,读取“任务队列”
  4. 主线程不断重复第三步
  5. 主线程阻塞,任务队列依旧能够被推入任务

(by:阮一峰的网络日志,再谈Event Loop)

Event Loop

主线程从“任务队列”中读取事件,不断循环

(by:阮一峰的网络日志,再谈Event Loop)

Macrotask 和 Microtask

macro-tasks :script(整体代码),setTimeout,setInterval,setImmediate,I/O,UI

 

micro-tasks :process.nextTick,Promises,Object.observe,MutationObserver(html5新特性)

在一个事件循环里,

这两个队列会分两步执行,

第一步会固定地执行一个(且仅一个)Macrotask任务,

第二步会执行整个Microtask队列中的所有任务。

 

用代码来感受

作用

Macrotasks : 代表一些离散的独立的工作,task结束后,浏览器继续其他工作如页面重渲染和垃圾回收等

Microtasks : 更新完成应用程序状态的较小任务,在UI重渲染之前执行某些任务,避免不必要的UI渲染

Vue 中 MutationObserver

var counter = 1
var observer = new MutationObserver(nextTickHandler)
var textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
    characterData: true
})
timerFunc = () => {
    counter = (counter + 1) % 2
    textNode.data = String(counter)
}

JS异步发展

  • Callback
  • Promise
  • Generator
  • Async function
  • rxjs ??
  • ......

Callback

  • 给匿名函数命名
  • 模块化
  • ...
getData(function(a){  
    getMoreData(a, function(b){
        getMoreData(b, function(c){ 
            getMoreData(c, function(d){ 
                getMoreData(d, function(e){ 
                    ...
                });
            });
        });
    });
});

Promise

// 没有 promise
a(getResultFromA, (aResult, err) => {
  if (!err) {
    b(getResultFromB, (bResult, err) => {
      if (!err) {
        c(getResultFromC, (cResult, err) => {
          if (!err) {
            // do something
          } else {
            throw err
          }
        })
      } else {
        throw err 
      }
    })
  } else {
    throw err
  }
})

// 用了 promise 后
new promise((resolve, reject) => {
  a(getResultFromA, (aResult, err) => {
    if (!err) resolve(aResult) else reject(err)
  })
})
.then(data => {
  return new Promise((resolve, reject) => {
    b(getResultFromB, (bResult, err) => {
      if (!err) resolve(bResult) else reject(err)
    })
  }
})
.then(data => {
  return new Promise((resolve, reject) => {
    c(getResultFromC, (cResult, err) => {
      if (!err) resolve(cResult) else reject(err)
    })
  }
})
.then(data => {
  // do something
})
.catch(err => {
  throw err
})
  • 解决了异步回调函数层层嵌套
  • 错误处理以及链式回调

Generator

// 定义 
var fetch = require('node-fetch');

function* gen(){
  var url = 'https://api.github.com/users/github';
  var result = yield fetch(url);
  console.log(result.bio);
}

// 使用
var g = gen();
var result = g.next();

result.value.then(function(data){
  return data.json();
}).then(function(data){
  g.next(data);
});
  • "协程"(coroutine),意思是多个线程互相协作,完成异步任务
  • 流程管理却不方便

Async

  1. 内置执行器
  2. 更好的语义
  3. 更广的适用性
  4. 返回值是Promise

Rxjs(流Stream)

Reactive Extensions for JavaScript

观察者+迭代器模式

Observables与Observer

  • 订阅:Observer通过Observable提供的subscribe()方法订阅Observable
  • 发布:Observable通过回调next方法向Observer发布事件

Thanks

参考:ECMAScript 6 入门(阮一峰)

最后谈一次 JavaScript 异步编程(brambles)

Tasks, microtasks,

queues and schedules What the heck is the event loop anyway?

Concurrency model and Event Loop Macrotasks and Microtasks

......

 

Made with Slides.com