2017-05-09
Async
异步发射器
很多时候,我们会遇到这种情况:
有多个异步操作,而且需要每个异步操作的返回值。
(比如 ajax获取用户名、ajax获取地址、ajax获取banner图片等等)
比如异步操作 a, b, c, d 然后是要 在 a 的success 里面写上 b, 然后在 b的success里面写上c吗?? (如下代码)
00a(A => {        // 异步操作 a 获得 A
01    b(B => {    // 异步操作 b 获得 B
02        c(C => {// 异步操作 c 获得 C
03            d(D => {
04                // 异步操作 d 获得 D
05                console.log(A, B, C, D); 
06            });
07        });
08    });
09});
很显然 这样很恼人、而且很不好。
  1. 缩进太长 自带混乱 debuff
  2. 三个异步操作所需时间是: a, b, c, d 三件异步操作时间之和 并不是取 a, b, c, d 四件事情里面的最大值
不能不行不可以

# 一个可行的方案

  1. 用数组保存需要做什么 (数组元素是函数
  2. 处理这个数组、执行里面的元素、并传递一个叫做 commit 的函数给他
  3. 当异步操作成功的时候 commit(obj) 以这种方式提交值给 commit 完成处理
  4. commit(obj) 会把 obj 里面的属性合并到 最终期望值 {} 上
以下是具体的实现

# todos

用数组保存异步操作
00var todos = [
01    function getUser(commit){ 
02        setTimeout(() => {
03            commit({  // 这里是异步结束的时候 利用 commit 把值回传 
04                name: 'eczn',
05                age: 20
06            }, 233); 
07        }); 
08    },
09    function getLoc(commit){
10        setTimeout(() => {
11            commit({
12                area: '广东广州GDUT某个地方'
13            });
14        }, 333); 
15    },
16    function getYourReaction(commit){
17        setTimeout(() => {
18            commit({
19                heSay: 'hello coder, nice to code you.'
20            });
21        }, 334); 
22    }
23];
执行 todos[0]
执行 todos[0]

# launcher

发射器,这里会并发全部的异步操作,并且定义了 commit
00function launcher(processors, cb){
01    var o = {}; 
02    var count = 0; 
03    if (processors.length === 0) cb(o); 
04
05    processors.forEach((func, idx) => {
06        func(function commit(asyncVal){
07            // 把 asyncVal 的所有属性合并到 o 上 
08            // ( 利用 Object.keys 获取对象全部属性名 )
09            Object.keys(asyncVal).forEach(key => {
10                o[key] = asyncVal[key]; 
11            }); 
12
13            count++; 
14            // 如果发射器全部发射完毕则调用回调函数 cb 并把 o 作为参数传递
15            if (count === processors.length) cb(o); 
16        }); 
17    }); 
18}

# 调用

00launcher(todos, function(ecznSay){
01    // todos 里面存放的异步操作的值由 commit 回调返回
02    // 全部回调跑完的时候 就会执行当前这段函数 并把期望值返回
03    console.log(ecznSay); 
04
05    // 按顺序输出
06    ['name', 'area', 'heSay'].forEach(key => {
07        console.log(`${key}: ${ecznSay[key]}`); 
08    }); 
09});
执行结果
执行结果

# 不足的地方

  1. 没有考虑失败 这里假设了一定可以得到返回值
  2. 无序并发,没有考虑异步操作的依赖性 这里假设了异步操作之间互不依赖

17 年 9 月更新, Promise 和 Async / Await 才是异步编程的终极方案,当时没接触到这个,构造的这个异步发射器跟 Promise.all 做的事是类似的。。




回到顶部