避免回调地狱和长链式then,快速实现具有继发关系的请求

2,131 阅读3分钟
这篇文章不是为了介绍回调地狱也不是介绍Promise,而是介绍如何实现具有继发关系的多个请求。
何为继发关系?
比如有三个请求A、B、C,B要等待A请求的结果再发起请求,C要等待B请求的结果再发起请求,也就是A - B - C有所关联,这就是继发关系。
问题的转移
一直以来,回调地狱是大问题,随着ES6的完成,Promise出现了,解决了回调地狱,但在请求具有继发关系的请求时,又出现了另一个问题,会出现长链式then。
async/await
现在我们可以使用ES7中的async/await了。
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
Async用来定义异步函数

语法:async function someName(){}
Await用来暂停异步函数的执行
语法:const step = async function someName(){...}
更多关于async函数: es6.ruanyifeng.com/#docs/async
下面直接上例子。
如果支持async,比如Typescript/Node 7.6+中,可以这样快速实现:
asyncRequest(requestArrs: any, context: any) {   
  const values = [];   
  let num = 0;   
  const req = async () => {   
    try {   
      for (const request of requestArrs) {   
        values[num] = await context[request](values[num - 1] || null);   
        num++;   
      }   
      return values[values.length - 1];   
    } catch (err) {   
      console.error(err);   
    }   
  };   
  return req;   
}   


const steps = {   
  step1(res) {   
    return new Promise((resolve, reject) => {   
      setTimeout(() => {   
        resolve(321);   
      }, 1000);   
    });   
  },   
  step2(res) {   
    return new Promise((resolve, reject) => {   
      setTimeout(() => {   
        resolve(123 + res);   
       }, 500);

    });   
   }   
};  


asyncRequest(['step1', 'step2'], steps)().then(res => {   
   console.log(res);  
});
asyncRequest函数的第一个参数是一个字符串数组,包含要执行的函数名称;第二个参数是这些函数的上下文,它返回一个异步函数,也就是上面的req函数,异步函数最终返回的是一个promise,所以你可以使用then。 在Node端如何还未支持async,但要支持ES6,可以借助Generator函数co库
const co = require('co');   


const asyncRequest = function(requestArrs, context) {   
  const values = [];   
  let num = 0;   
  const req = function* () {   
    try {   
      for (const request of requestArrs) {   
        values[num] = yield context[request](values[num - 1] || null);   
        num++;   
      }   
      return values[values.length - 1];   
    } catch (err) {   
      console.error(err);   
    }   
  };   
  return req;  
}    


const steps = {   
  step1(res) {   
    return new Promise((resolve, reject) => {   
      setTimeout(() => {   
        resolve(321);   
      }, 1000);   
    });   
  },   
  step2(res) {   
    return new Promise((resolve, reject) => {   
      setTimeout(() => {   
        resolve(123 + res);   
      }, 500);   
    });   
  }   
};   
const async = asyncRequest(['step1', 'step2'], steps);   
co(async).then(res => {   
  console.log(res)   
});
就是这么简单,只需定义多个请求函数,就可以完成继发关系的请求,再也不用多层嵌套或长链式then了。

如果有疑问,欢迎在下方评论留言!