js异步编程发展史

我们都知道Js主线程是单线程的,所以异步处理在js中就显得尤为重要。异步处理的发展路程是:CallBack
回调处理——事件监听(类似jquery,on)——发布/订阅(Ben Alman的Tiny Pub/Sub,这是jQuery的一个插件)
——Promise——generator(搭配co库)——ES7终极async,await。异步处理也从最初的横向发展的胖子到纵向发展
的大个子,到今天我们能像写同步代码一样写异步逻辑。

1.CallBack即“回调函数”

即异步操作执行完后触发执行的函数,例如:$.get("http://api.xxxx.com/xxx",callback);当请求完成时就
会触发callback函数。callback可以完成异步操作。
$.ajax({
    url: "type",
    data:1,
    success: function (a) {
        $.ajax({
            url: "list",
            data:a,
            success: function (b) {
                $.ajax({
                    url: "content",
                    data:b,
                    success: function (c) {
                        console.log(c)
                    }
                })
            }
        })
    }
})
这就是传说中的“回调地狱”,可读性差,不便于后期维护,易出错,横向发展的大胖子。


2、事件监听、发布/订阅。可以看看阮一峰老师的《Javascript异步编程的4种方法》:
http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html

3.Promise
Promise就是为解决“回调地狱”而生的,。Promise对象简单说就是一个容器,里面保存着某个未来才会结束的事件
(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 
提供统一的 API,各种异步操作都可以用同样的方法进行处理。
const promise = new Promise(function(resolve, reject) 
{
  // ... some code
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,
由 JavaScript 引擎提供,不用自己部署。resolve函数的作用是,将Promise对象的状态从“未完成”变为
“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),
在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。Promise实例生成以后,
可以用then方法分别指定resolved状态和rejected状态的回调函数。promise.then(function(value) {
  // success
}, function(error) {
  // failure
});
then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,
第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。
这两个函数都接受Promise对象传出的值作为参数。
这样采用 Promise,解决“回调地狱”问题,比如node中连续读取多个文件,写法如下。
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);
});
可见这种写法要比CallBack写法直观的多。从横向变成了纵向发展。


4.Generator(一般要搭配co库,否则也是横向发展)
函数Genrator 函数要用* 来比标识,yield关键字表示暂停。将函数分割出好多个部分,调用一次next就会继续
向下执行。返回结果是一个迭代器,迭代器有一个next方法。
function* read() {
    console.log(1);
    let a = yield '123';
    console.log(a);
    let b = yield 9
    console.log(b);
    return b;
}
let it = read();
console.log(it.next('213')); // 1 {value:'123',done:false}
console.log(it.next('100')); // 100 {value:9,done:false}
console.log(it.next('200')); // 200 {value:200,done:true}
console.log(it.next('200')); // {value:200,done:true}

yield后面跟着的是value的值,next里面的参数会作为上一个yield的返回值,并且第一次next传值是无效的。

处理异步的时候Generator和Promise搭配使用。这里用到一个bluebird库,用来把一个异步方法转为Promise,
避免了每次需要在异步方法外new Promise()。

let bluebird = require('bluebird');
let fs = require('fs');
let read = bluebird.promisify(fs.readFile);//将readFile转为Promise对象的实例
function* r() {
    let content1 = yield read('./2.promise/1.txt', 'utf8');
    let content2 = yield read(content1, 'utf8');
    return content2;
}
这样看起来是我们想要的样子,但是只写成这样还不行,想得到r()的结果还要对函数进行处理
function co(it) {  //co库的实现
    return new Promise(function (resolve, reject) {
        function next(d) {
            let { value, done } = it.next(d);
            if (!done) {
                value.then(function (data) {
                    next(data)
                }, reject)
            } else {
                resolve(value);
            }
        }
        next();
    });
}
co(r()).then(function (data) {
    console.log(data)
})


5.async-await函数ES2017 标准引入了 async 函数,使得异步操作变得更加方便。async 函数是什么?
一句话,它就是 Generator 函数的语法糖。
let bluebird = require('bluebird');
let fs = require('fs');
let read = bluebird.promisify(fs.readFile);
async function r(){
    try{
        let content1 = await read('./2.promise/100.txt','utf8');
        let content2 = await read(content1,'utf8');
        return content2;
    }catch(e){ // 如果出错会catch
        console.log('err',e)
    }
}
async函数其实就是将 Generator 函数的星号(*)替换成async,将yield替换成await。
async函数返回的是也是promiser().then(function(data){
    console.log(data);
},function(err){

})

复制代码

转载于:https://juejin.im/post/5b001be0f265da0b9127b4df

你可能感兴趣的:(js异步编程发展史)