js之异步操作(事件循环机制及异步处理方式含promise)

最近学习es6 看到promise和generater,最后发现他们的共同点都是通过维护状态来解决异步的一种方式,

由于js单线程运行的特点,所以前端编程一直离不开异步这个概念,先把这个知识点进行梳理。

先看同步问题,同步很简单就是程序排队执行,但同步会存在阻塞问题
同步阻塞:

// 这是一个阻塞式函数, 将一个文件复制到另一个文件上
function copyBigFile(afile, bfile){
    var result = copyFileSync(afile,bfile);
    return result;
}

如上所示若copyFileSync用时一小时那么一小时后copyBigFile才会有返回结果,这就是同步阻塞。

所以js异步的出现来解决同步阻塞问题

异步概念:异步就是cpu跳过等待,先处理后续的任务(JavaScript 语言对异步编程的实现,就是回调函数)
先看js在单线程下如何实现异步操作:

js之异步操作(事件循环机制及异步处理方式含promise)

 

如上图为JS运行机制图(事件循环示例图),流程如下:
 

step1:主线程读取JS代码,此时为同步环境,形成相应的堆和执行栈;

    step2:  主线程遇到异步任务,指给对应的异步进程进行处理(WEB API);

    step3:  异步进程处理完毕(Ajax返回、DOM事件处罚、Timer到等),将相应的异步任务推入任务队列;

    step4: 主线程执行完毕,查询任务队列,如果存在任务,则取出一个任务推入主线程处理(先进先出);

    step5: 重复执行step2、3、4;称为事件循环。

  执行的大意:

    同步环境执行(step1) -> 事件循环1(step4) -> 事件循环2(step4的重复)…

  其中的异步进程有:

    a、类似onclick等,由浏览器内核的DOM binding模块处理,事件触发时,回调函数添加到任务队列中;

    b、setTimeout等,由浏览器内核的Timer模块处理,时间到达时,回调函数添加到任务队列中;

    c、Ajax,由浏览器内核的Network模块处理,网络请求返回后,添加到任务队列中。

知道原理后再看常见js中异步处理方式:
除开上面提到的 事件、setTimeout、Ajax请求较熟悉的外这里介绍而是es6 的几种异步处理方式:

1.Promise 
回调函数本身并没有问题,它的问题出现在多个回调函数嵌套。假定读取A文件之后,再读取B文件,代码如下。

fs.readFile(fileA, 'utf-8', function (err, data) {
  fs.readFile(fileB, 'utf-8', function (err, data) {
    // ...
  });
});

不难想象,如果依次读取两个以上的文件,就会出现多重嵌套。代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理。因为多个异步操作形成了强耦合,只要有一个操作需要修改,它的上层回调函数和下层回调函数,可能都要跟着修改。这种情况就称为"回调函数地狱"(callback hell)。

Promise 对象就是为了解决这个问题而提出的。它不是新的语法功能,而是一种新的写法,允许将回调函数的嵌套,改成链式调用。采用 Promise,连续读取多个文件,写法如下。

var readFile = require('fs-readfile-promise');

readFile(fileA)
.then(function (data) {
  console.log(data.toString());
})
.then(function () {
  return readFile(fileB);
})
.then(function (data) {
  console.log(data.toString());
})
.catch(function (err) {
  console.log(err);
});

 

上面代码中,我使用了fs-readfile-promise模块,它的作用就是返回一个 Promise 版本的readFile函数。Promise 提供then方法加载回调函数,catch方法捕捉执行过程中抛出的错误。

可以看到,Promise 的写法只是回调函数的改进,使用then方法以后,异步任务的两段执行看得更清楚了,除此以外,并无新意。
当然,还有Generator函数,比promise更加优化,后续补充。

 

上一篇:Python中的文件读取在Windows 7中应该停止


下一篇:APP专用密码app-specific password生成步骤分享