浅析JavaScript异步到底是怎么实现的?( 三 )

  • setTimeout、setInterval的函数调用得到其返回值 。由于两个函数都是异步的,即:调用时序和程序的主流程是相对独立的,所以没有办法在主体里面等待它们的返回值,它们被打开的时候程序也不会停下来等待,否则也就失去了setTimeout及setInterval的意义了,所以用return已经没有意义,只能使用callback 。callback的意义在于将timer执行的结果通知给代理函数进行及时处理 。
  • JavaScript中的那些异步操作JavaScript既然有很多的辅助线程,不可能所有的工作都是通过主线程去做,既然分配给辅助线程去做事情 。
    XMLHttpRequest
    XMLHttpRequest对象应该不是很陌生的,主要用于浏览器的数据请求与数据交互 。XMLHttpRequest对象提供两种请求数据的方式,一种是 同步,一种是 异步 。可以通过参数进行配置 。默认为异步 。
    对于 XMLHttpRequest这里就不作太多的赘述了 。
    var xhr = new XMLHttpRequest();xhr.open("GET", url, false); //同步方式请求xhr.open("GET", url, true); //异步xhr.send();同步 Ajax请求:
    当请求开始发送时,浏览器事件线程通知 主线程,让 Http线程发送数据请求,主线程收到请求之后,通知 Http线程发送请求,Http线程收到 主线程通知之后就去请求数据,等待服务器响应,过了 N年之后,收到请求回来的数据,返回给 主线程数据已经请求完成,主线程把结果返回给了 浏览器事件线程,去完成后续操作 。
    异步 Ajax请求:
    当请求开始发送时,浏览器事件线程通知,浏览器事件线程通知 主线程,让 Http线程发送数据请求,主线程收到请求之后,通知 Http线程发送请求,Http线程收到 主线程通知之后就去请求数据,并通知 主线程请求已经发送,主进程通知 浏览器事件线程已经去请求数据,则
    浏览器事件线程,只需要等待结果,并不影响其他工作 。
    setInterval&setTimeout
    setInterval与 setTimeout同属于异步方法,其异步是通过回调函数方式实现 。其两者的区别则 setInterval会连续调用回调函数,则 setTimeout会延时调用回调函数只会执行一次 。
    setInterval(() => {alert(1)},2000)// 每隔2s弹出一次1setTimeout(() => {alert(2)},2000)// 进入页面后2s弹出2,则不会再次弹出
    requestAnimationFarme
    requestAnimationFrame字面意思就是去请求动画帧,在没有 API之前都是基于 setInterval,与 setInterval相比,requestAnimationFrame最大的优势是由系统来决定回调函数的执行时机 。具体一点讲,如果屏幕刷新率是 60Hz,那么回调函数就每 16.7ms被执行一次,如果刷新率是 75Hz,那么这个时间间隔就变成了 1000/75=13.3ms,换句话说就是,requestAnimationFrame的步伐跟着系统的刷新步伐走 。它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引起丢帧现象,也不会导致动画出现卡顿的问题 。
    举个小例子:
    var progress = 0;//回调函数function render() {progress += 1; //修改图像的位置if (progress < 100) { //在动画没有结束前,递归渲染window.requestAnimationFrame(render);}}//第一帧渲染window.requestAnimationFrame(render);Object.observe - 观察者
    Object.observe是一个提供数据监视的 API,在 chrome中已经可以使用 。是 ECMAScript 7 的一个提案规范,官方建议的是 谨慎使用级别,但是个人认为这个 API非常有用,例如可以对现在流行的 MVVM框架作一些简化和优化 。虽然标准还没定,但是标准往往是滞后于实现的,只要是有用的东西,肯定会有越来越多的人去使用,越来越多的引擎会支持,最终促使标准的生成 。从 observe字面意思就可以知道,这玩意儿就是用来做观察者模式之类 。
    var obj = {a: 1};Object.observe(obj, output);obj.b = 2;obj.a = 2;Object.defineProperties(obj, {a: { enumerable: false}}); //修改属性设定delete obj.b;function output(change) {console.log(1)}PromisePromise是对异步编程的一种抽象 。它是一个代理对象,代表一个必须进行异步处理的函数返回的值或抛出的异常 。也就是说 Promise对象代表了一个异步操作,可以将异步对象和回调函数脱离开来,通过 then方法在这个异步操作上面绑定回调函数 。
    在Promise中最直观的例子就是 Promise.all统一去请求,返回结果 。
    var p1 = Promise.resolve(3);var p2 = 42;var p3 = new Promise(function(resolve, reject) {setTimeout(resolve, 100, 'foo'); });Promise.all([p1, p2, p3]).then(function(values) {console.log(values);});// expected output: Array [3, 42, "foo"]Generator&Async/AwaitES6的 Generator却给异步操作又提供了新的思路,马上就有人给出了如何用 Generator来更加优雅的处理异步操作 。Generator函数是协程在 ES6的实现,最大特点就是可以交出函数的执行权(即暂停执行) 。整个 Generator函数就是一个封装的异步任务,或者说是异步任务的容器 。异步操作需要暂停的地方,都用yield语句注明 。Generator函数的执行方法如下 。


    推荐阅读