Javascript异步编程的四种方式

在javascript开发过程中,我们不可避免的会遇到一些异步编程的情景,无论是前端的ajax请求还是,node的各种异步api,下文是在工作学习过程中总结的关于javascript异步编程集中常见方式用法的总结

回调函数

使用回调函数是最常见的一种形式

//jQuery ajax
$.get('test.php',res=>{
    //数据处理
});

//node异步读取文件
let fs=require('fs');
     fs.read('file/path',(error,data)=>{
        //数据处理
    });

回调函数就是定义函数的时候,将另外一个函数(回调函数)作为参数传入,在异步操作执行完成后就会执行该回调函数,从而可以保证在回调函数中的操作可以在异步执行完成之后执行。回调函数的缺点是当需要执行多个异步操作时,需要将多个回调函数嵌套在一起,组成代码结构上的混乱,可读性较差,被称为“回调地狱”。

func1(data1,()=>{
    func2(data2,()=>{
        func3(data3,()=>{
             //业务逻辑
         });
    });
});

Promise

Promise以一种链式调用的方法来组织异步代码,可以将原来以回调函数形式调用的异步操作,改写为promise链式调用

//jQuery ajax promise
 $('test.html').then(res=>{
    //业务逻辑
}).then(res=>{
    //业务逻辑
});

我们还可以利用ES6的Promise构造函数,自定义Promise

 let resultA=new Promise((resolve,reject)=>{
          let flag=Math.random()<0.5;
          setTimeout(()=>{
            if(flag){
              resolve({
                result:true,
                msg:'ok'
              });
            }
            else{
              reject({
                result:false,
                msg:'error'
              });
            }
    },0);  
  });
    
  resultA.then(res=>{
          console.log(res.msg);
          return Promise.resolve('I am from this first promise');
        }).catch(err=>{
              console.log(err.msg);
        }).then(res=>{
          console.log(res);
        });

在最新版本的node(node 8.0+)环境里,还可以利用util.promisify方法将回调函数形式的函数直接转换为Promise形式。

 let util = require('util');
 let fs = require('fs');
 let readFilePromise = util.promisify(fs.readFile);
 readFilePromise('demo.js','utf-8').then((data)=>{
   console.log(data);
 });

Generators

node的著名开发者TJ利用ES6的新特性生成器开发了一个异步控制控制工具co,Generators生成器,借助co可以将异步代码的写法写成类似同步代码的形式。

let util = require('util');
let fs = require('fs');
let co=require('co');
let readFilePromise = util.promisify(fs.readFile);
co(function *(){
    let baz = yield readFilePromise('baz.js','utf-8');
        console.log(baz);
    let foo = yield readFilePromise('foo.js','utf-8');
        console.log(foo);
});

可以看出Generator的优点显而易见,它可以使异步代码写的非常清晰,可读性很高,缺点使依赖第三方库才能使用该特性。

Async/Await

node7.6以上的版本引入了一个es7的新特性 Async/Await,专门用来进行异步控制,下面先看一简单的个例子

let delay = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    console.log('test');
    resolve('msg from promise');
  });
});

let baz = async ()=>{
  let res = await delay;
  console.log(res);//'msg from promise'
};

baz();

首先我们需要使用async关键字定义一个包含异步代码执行的函数,在promise形式你的异步执行函数前面使用await关键字,就可以将异步写成同步的操作形式。
相比Generators生成器,由于Async/Await使原生的异步控制方案,所以比较推荐使用的。

posted @ 2017-07-07 09:40  joe_ice  阅读(563)  评论(0)    收藏  举报