vaakian / vaakian.github.io

some notes
https://vaakian.github.io
3 stars 0 forks source link

Promise #21

Open vaakian opened 2 years ago

vaakian commented 2 years ago

Promise中resolve一个Promise

从例子中,显然能发现如果Resolve/Reject传过来的同样是Promise,那么继续接管当前Promise,直到Promise完成再将数据交给第一个Then。


const p1 = () => {
    return Promise.resolve(new Promise((resolve) => {
        setTimeout(() => resolve(Promise.resolve('test')), 500)
    }))
}

p1().then(p2 => {
    console.log(p2)
    return 'from p2'
    // p2.then(data => console.log(data)) // TypeError: p2.then is not a function
}).then(p3 => {
    console.log(p3)
    return Promise.reject('reject from p3')
}).catch(p4 => {
    console.log(p4)
    return 'from p4'
}).then(p5 => {
    console.log(p5)
})
vaakian commented 2 years ago

Promise.all && Promise.race

Promise.all仅当所有promise都被resolve后触发then,结果得到结果数组。 该数组与传入的promise顺序一致,不管谁先被resolve。 否则catch收到第一个出现错误的promise

let p1 = new Promise((resolve) => {
    setTimeout(() => resolve(1), 500)
})

let p2 = new Promise((resolve) => {
    setTimeout(() => resolve(2), 100)
})

let p3 = Promise.resolve(3)

Promise.all([p1, p3, p2]).then((result) => {
    console.log(result)
}).catch((error) => {
    console.log(error)
})
// [1, 3, 2]

Promise.race捕获最先被resolve的promise

vaakian commented 2 years ago

实现请求超时拦截报错

具体可以通过Promise.race实现 第一个版本,能够正常捕获错误。

function fetch() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(100);
        }, 200);
    });
}
function counter(timeout) {
    return new Promise((resolve, reject) => {
        setTimeout(() => reject('http request timeout'), timeout);
    })
}
Promise.race([fetch(), counter(100)]).then(data => {
    console.log(data);

}).catch(err => {
    console.log(err);
})

但这里错误捕获后,fetch并不会被中断,所以会继续请求下去,只是不会再被程序处理。

所以在counter执行后,应该取消fetch请求。

let controller = new AbortController();
let signal = controller.signal;
function someHttpRequest(signal) {
    return fetch('https://github.com', {signal});
}
function counter(timeout, controller) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {reject('http request timeout'); controller.abort();}, timeout);
    })
}
Promise.race([someHttpRequest(signal), counter(10, controller)]).then(data => {
    console.log(data);

}).catch(err => {
    console.log(err);
})

当然实现超时有更简单的方法,这里只是一个应用。如:

function someHttpRequest(url, timeout, config = {}) {
    let controller = new AbortController();
    let signal = controller.signal;
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            controller.abort();
            reject(new Error('request timeout'));
        }, timeout);
        resolve(fetch(url, { ...config, signal }));
    })
}
someHttpRequest('https://github.com', 10)
    .then(data => console.log(data))
    .catch(err => console.log(err));

image image

vaakian commented 2 years ago

Promise.all是并行,实现Promise.run串行?

vaakian commented 2 years ago

实现串行promiseAll


const serialPromises = function (promises = []) {
    return new Promise((resolve, reject) => {
        let result = []
        function inner(i) {
            if (i >= promises.length) {
                // promise全部执行完毕,返回结果
                resolve(result)
            } else {
                promises[i]().then(data => {
                    result.push(data)
                    inner(i + 1)
                // 一旦遇到错误,就直接reject
                }).catch(err => reject(err))
            }
        }
        inner(0)
    })

}

测试

function p1() {
    console.log('p1')
    return new Promise((resolve) => {
        setTimeout(() => resolve('1'), 2000)
    })
}
function p2() {
    console.log('p2')
    return Promise.reject('2')
}

function p3() {
    console.log('p3')
    return Promise.resolve('3')

}

serialPromises([p1, p2, p3])
    .then(resultArr => {
        console.log(resultArr)
    })
    .catch(err => console.log(err))