需求

两个异步请求同时发出,两个请求都返回时再做处理

实现

这里的方法仅提供思路,只做请求成功处理

方法一

使用Promise.all
const startTime = new Date().getTime() 
function request(time) {  
    return new Promise(resolve => {  
        setTimeout(() => {  
            resolve(time) 
        }, time) 
    }) 
} 
let request1 = request(3000) 
let request2 = request(2000) 
Promise.all([request1, request2]).then(res => {  
    console.log(res, new Date() - startTime) // [ 3000, 2000 ] 3001 }) 
})

方法二

自定义状态,在回调中判断返回状态,待2个请求都有返回值时再做处理
const startTime = new Date().getTime() 
function request(time) {  
    return new Promise(resolve => {  
        setTimeout(() => {  
            resolve(time) 
        }, time) 
    }) 
} 
let state = [undefined, undefined] 
let request1 = request(3000) 
let request2 = request(2000) 
request1.then(res => {  
    state[0] = res 
    process() 
}) 
request2.then(res => {  
    state[1] = res 
    process() 
}) 
function process() {  
    if (state[0] && state[1]) {  
        console.log(state, new Date() - startTime) // [ 3000, 2000 ] 3001 
    } 
} 

方法三 generator,yield

const startTime = new Date().getTime() 
function ajax(time, cb) {  
    setTimeout(() => cb(time), time) 
} 
function request(time) {  
    ajax(time, data => {  
        it.next(data); 
    }) 
} 
function* main() {  
    let request1 = request(3000); 
    let request2 = request(2000); 
    let res1 = yield request1 
    let res2 = yield request2
    console.log(res1, res2, new Date() - startTime) // 2000 3000 3001 
} 
let it = main(); 
it.next(); 

这个地方有点问题,因为request2耗时较短,会先返回,也就是先执行it.next(2000),导致res1获得了request2的返回值

若使用co函数,则不会存在这个问题,因为co是在promise.then函数中才执行it.next(),相当于it.next()是链式调用

generator使用co函数
const co = require('co') 
const startTime = new Date().getTime() 
function request (time) {  
    return new Promise(resolve => {  
        setTimeout(() => {  
            resolve(time) 
        }, time) 
    }) 
} 
co(function* () {  
    let request1 = request(3000); 
    let request2 = request(2000); 
    let res1 = yield request1 
    let res2 = yield request2
    console.log(res1, res2, new Date() - startTime) // 3000 2000 3001 
}) 

有了co函数,就不需要生成it和执行next方法了;

co的原理其实也简单,就是递归执行next,直到done为true;
如果next返回的value是Promise,则在then函数中执行next,若不是Promise,直接执行next函数

下面是co函数的简版手写实现
function co(func) {  
    let it = func() 
    let t = it.next() 
    next() 
    function next() { 
        if (t.done) return 
        if (t.value instanceof Promise) {  
            t.value.then(res => {  
                t = it.next(res) 
                next() 
            }) 
        } else {  
            t = it.next(t.value) next() 
        } 
    } 
} 

方法四


有了generator,很容易想到async/await,毕竟async/await就是由generator实现的
// setTimeout模拟异步请求,time为请求耗时 
const startTime = new Date().getTime() 
function request (time) {   
    return new Promise(resolve => {   
        setTimeout(() => {   
            resolve(time)  
        }, time)  
    }) 
} 
(async function () {
    // 注意这里一定不能写成 await request(3000),否则就是同步执行了  
    let request1 = request(3000)  
    let request2 = request(2000)  
    let res1 = await request1
    console.log(res1, new Date() - startTime) // 3000 3001  
    let res2 = await request2
    console.log(res2, new Date() - startTime) // 2000 3005 
})()