2

其实就是照着网上的介绍和co的源码实现了一个自己用的前端async模块。支持RequireJS和SeaJS,支持$.ajax。
有喜欢co但是不知道怎么用的前端朋友可以拿去用。

co模块的意义和原理在sf上已经有详细的介绍了,具体参见:
http://segmentfault.com/a/1190000002732081

用法:

async(function* () {
    var a = yield Promise.resolve(1);
    console.log(a);
    var b = yield [Promise.resolve(2), Promise.resolve(3)];
    console.log(b);
    return 4;
}).then(function (value) {
    console.log(value);
}).catch(function (e) {
    // 异常处理
});

// 输出结果应该为 1 [2,3] 4

源码:

/*global exports*/
'use strict';
(function (factory) {
    // 各种模块加载方式的处理
    if (typeof define === 'function' && define.amd) {
        define([], factory);
    } else if (typeof define === 'function' && define.cmd) {
        define(function (require, exports, module) {
            module.exports = factory(jQuery);
        });
    } else if (typeof exports === 'object') {
        exports.async = factory();
    } else {
        // window.async=factory();
    }
}(function () {
    // 下面这俩函数是有用的
    function async(generator) {
        // 主Promise
        return new Promise(function (resolve, reject) {
            var g = generator();
            /**
             *  该函数会在异步过程执行完毕后被调用,会唤醒主函数继续执行到下一个yield或return为止。
             *  参数val为异步过程的结果,即promise.result。
             *  返回值为主函数内yield或return的结果,
             *  如果是yield则必须为promise或可被autoPack包装的对象,或者包含前两者的数组
             */
            function next(val) {
            
                // 将上次运行结果返回给主函数,令主函数继续执行到下一处中断,并将结果存入result
                var result = g.next(val);
                // 暂存主函数运行结果
                var promise = result.value;
                // 判断主函数是否执行完毕,执行完毕则调用resolve完成主Promise,否则继续执行
                if (!result.done) {
                    // 判断主函数提供的参数是否为数组,
                    // 如果不是数组则用autoPack封装后通过then(next)绑定下一步流程。并通过catch(reject)抛出异常
                    // 如果是数组则对每个成员进行封装后用Promise.All打包,然后继续执行。
                    if (promise instanceof Array) {
                        Promise.all(promise.map(autoPack)).then(next).catch(reject);
                    } else {
                        autoPack(promise).then(next).catch(reject);
                    }
                } else {
                    resolve(promise);
                }
            }

            // 捕获并通过reject抛出异常
            try {
                next();
            } catch (e) {
                reject(e);
            }
        })
    }

    // 自动打包,可以将第三方实现的Promise工具打包为ES6标准的Promise
    // 目前仅支持jQuery.Promise
    function autoPack(target) {
        // 包装$.ajax
        if (target.error) {
            return new Promise(function (resolve, reject) {
                target.done(resolve).error(reject);
            })
        } else {
            return target;
        }
    }

    return async;
}));

WoodenSail
1.3k 声望18 粉丝