co.js - 让异步代码同步化

近期在全力开发我的网站,而且又沉淀了一些先后端的技术。近期会频繁更新。javascript

这篇文章首发于个人我的网站:据说 - https://tasaid.com,建议在个人我的网站阅读,拥有更好的阅读体验。html

这篇文章与 博客园 和 Segmentfault 共享。前端

前端开发QQ群:377786580java

coTJ 大神所编写的 JavaScript 异步解决方案的库,用于让异步的代码 "同步化"。git

它构建在如下两个基础上,这篇文章不会详细讲解这 2 个知识点:github

Generator 和 co

首先咱们简单了解下 generator异步

// 定义一个 generators
function* foo(){
    yield console.log("bar");
    yield console.log("baz");
}

var g = foo();
g.next(); // prints "bar"
g.next(); // prints "baz"

简单来讲,generator 实现了状态暂停/函数暂停 —— 经过 yield 关键字暂停函数,并返回当前函数的状态。ide

co 实现了 generator自动执行,咱们使用 coPromise 修改上面的代码:

var co = require('co');

function* foo() {
    yield Promise.resolve(console.log("bar"));
    yield Promise.resolve(console.log("baz"));
}

var co = require('co');
co(foo);

有人可能要说 "我本身写个循环执行 next 不也能够么? 为何一个循环还要依赖一个库?"

co 有个使用条件:generator 函数的 yield 命令后面,只能是 Thunk 函数或 Promise 对象。

正是这个条件,让 co 强悍无比。

Callback

咱们一步一步来看异步,首先使用 回调函数/Callback 的方式封装一个常见的 ajax 异步任务:

function ajax(q, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
            callback(xhr.responseText);
        }
    }
    xhr.open("GET", "query?q=" + q);
}

咱们使用 回调函数 的方式连续发 2 条请求:

ajax('foo', function (foo) {
    console.log(foo);
    ajax('bar', function (bar) {
        console.log(bar);
    });
});

这是 js 中最典型的异步处理方案。

Promise

再使用 Promise 封装异步 ajax,让回调函数扁平化:

function ajax(q, callback) {
    // 使用 Promise 封装
    return new Promise(function (resolve) {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4 && xhr.status == 200) {
                resolve(xhr.responseText);
            }
        }
        xhr.open("GET", "query?q=" + q);
    });
}

而后修改请求代码,扁平化异步代码:

ajax('foo')
    .then(function (foo) {
        console.log(foo);
        return ajax('bar')
    })
    .then(function (bar) {
        console.log(bar);
    });

co

最后,让咱们见一下 co 的强悍之处吧。咱们使用 co.js 来修改请求代码:

var co = require('co');

co(function* () {
    var foo = yield ajax('foo');
    console.log(foo);

    var bar = yield ajax('bar');
    console.log(bar);
});

最终咱们的异步任务,在代码中同步化了。

对于异步代码来讲,回调函数是最基础的方案,带来的弊端也显而易见。Promise 让代码扁平化,而 co 让代码同步化。

这篇文章首发于个人我的网站:据说 - https://tasaid.com,建议在个人我的网站阅读,拥有更好的阅读体验。

这篇文章与 博客园 和 Segmentfault 共享。

前端开发QQ群:377786580

参考和引用