npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

combine-async-error

v0.2.0

Published

将.then、.catch、try catch组合在一起,并在复杂的嵌套请求中体现combine-async-error工具类的强大

Readme

摘要

开发中无论怎样都会产生网络请求,这样一来自然也就避免不了大量使用thencatchtry catch来捕获错误,而捕获错误的代码量是随着网络请求的增多而增多,那应该如何优雅的系统性捕获某个网络请求中所对应的所有错误呢?

需求

现有嵌套请求如下:

先请求书本作者---再请求书本价格---再请求书本出版社

  • 当成功时则需要返回所有结果
  • 当某次请求失败时,需要抛出具体的错误原因

模拟异步

在这里我们称requestAuthorrequestPricerequestPress为请求函数。且interface用于模拟某次请求的成功与否

// 标识每次请求的成功与否
const interface = [true, false, false]

const book = '三国演义'
// 请求书本的作者信息接口
const requestAuthor = () => new Promise((res, rej) => {
    setTimeout(() => {
        if (interface[0]) return res(`《${book}》的作者是罗贯中`)
        rej(`请求《${book}》的【作者】时出错,你现在可以做出具体的操作了`)
    }, 1000)
})
// 请求书本的价格信息接口
const requestPrice = () => new Promise((res, rej) => {
    setTimeout(() => {
        if (interface[1]) return res(`《${book}》的价格是99元`)
        rej(`请求《${book}》的【价格】时出错,你现在可以做出具体的操作了`)
    }, 1000)
})
// 请求书本的出版社信息接口
const requestPress = () => new Promise((res, rej) => {
    setTimeout(() => {
        if (interface[2]) return res(`《${book}》的出版社是人民邮电出版社`)
        rej(`请求《${book}》的【出版社】时出错,你现在可以做出具体的操作了`)
    }, 1000)
})

Promise

requestAuthor()
    .then(data => {
        console.log('第一次请求', data)
        return requestPrice()
    })
    .then(data => {
        console.log('第二次请求', data)
        return requestPress()
    })
    .then(data => {
        console.log('第三次请求', data)
    })
    .catch(e => console.log('请求出错', e))

async的实现方式与上述代码大致相同,所以不再给出

使用链式then的方式,在我看来,有以下问题

  • 如果想在第三次请求中得到前面两次的请求结果,可能需要对每个then的返回值以及请求函数进行包装,或使用额外的环境进行存储
  • 如果想让某个请求函数在出错时,继续往下执行,这可能就需要对Promise作一番处理
  • 现在只是三次嵌套请求,如果继续增加则会导致then也继续增加

综上所述,现在给出combine-async-error的解决方案

combine-async-error

安装

npm install combine-async-error

入门

import combineAsyncError from 'combine-async-error'

const asyncQueue = [requestAuthor, requestPrice, requestPress]
const end = data => console.log(data)

combineAsyncError(asyncQueue)
	.then(end)

参数说明

接收两个参数

  • awaits:异步任务队列
  • config:配置项

awaits

awaits必须是一个数组,该数组中的每位成员必须是函数或对象,举例

const asyncQueue = [ requestAuthor ]
const end = data => console.log(data)

combineAsyncError(asyncQueue)
	.then(end)

awaits是对象时,格式如下

const asyncQueue = [
    requestAuthor,
    {
        func: requestPrice,
        args: ['鲨鱼辣椒'],
        callback: Function.prototype
    }
]
const end = data => console.log(data)

combineAsyncError(asyncQueue)
    .then(end)

func为要执行的请求函数

[args]表示当执行请求函数时要传递的参数;可选

[callback]会在请求函数执行完毕时调用;可选

config

传入combineAsyncError的配置项,如不传入,则全部使用默认配置项

配置项

isCheckTypes

在设计combine-async-error时,关于传入的参数是否进行校验,其实是存在一些负面影响的,为此,combine-async-error主动添加了isCheckTypes配置项,如果该配置项的值为false,则不对入参进行检查,反之进行严格的类型检查。如果可以确保传入的类型始终是正确的,那么强烈建议你将该配置项更改为false;默认为true

由于JavaScript中存在隐式类型转换,所以即使你指定了isCheckTypes为true,combine-async-error也不会对传入的第二个参数(config)进行检查

isCheckTypes: true

acc

acc: () => {}

如果指定了该值为函数,则所有请求完成后会执行该函数,此回调函数会收到最终的请求结果

如果未指定该值,则combine-async-error返回一个Promise对象,你可以在它的then方法中得到最终的请求结果

forever

遇到错误时,是否继续执行(发出请求)。无论是嵌套还是并发请求模式,该配置项始终生效

forever: false

pipes

single

后一个请求函数是否接收前一个请求函数的结果

whole

后一个请求函数是否接收前面所有请求函数的结果

wholetrue时,single无效,反之有效

pipes: {
    single: false,
    whole: true
}

all

combine-async-error应该得到原有的扩展,为此它支持新的配置项all,如果为all指定了order值,则传入combine-async-error的请求数组会并发执行,而不是继续以嵌套的形式执行

下面的写法相当于使用了all的默认配置,因为all的值默认为false

all: false // 嵌套请求

下面的写法则是开启了并发之旅all为一个对象,其order属性决定并发的请求结果是否按照顺序来存放到最终数组中

all: {
	order: true
}

关于order的使用,举例如下

// 假设requestAuthor始终会在3-6秒钟之内返回请求结果
const requestAuthor = () => {}
// 假设requestPrice始终会在1秒钟之内返回请求结果
const requestPrice = () => {}

const getInfo = [requestAuthor, requestPrice]
combine-async-error(getInfo, {
	all: {
		order: true
	}
})

由于你指定了ordertrue,那么在最终的请求结果数组result中,requestAuthor的请求结果会作为result的第一个成员出现,而requestPrice的请求结果则会作为该数组的第二个成员出现,这是因为order始终会保证resultgetInfo的顺序一一对应,即使requestPrice是最先执行完的请求函数

如果指定了orderfalse,则最先执行完的请求函数所对应的结果就会在result中越靠前;在上例中requestPrice的请求结果会出现在result的第一个位置

requestCallback

requestCallback: {
	always: false,
	success: false,
	failed: false
}

always表示无论请求函数是成功还是失败,都会在拿到请求结果后执行为该请求函数提前指定好的callback,此callback会收到当前请求函数的结果

success表示只有当请求函数成功时,才会去执行提前执行好的callback,并且callback会收到当前请求函数执行成功的结果;failed则表示失败,与success同理

例如,当传入请求函数的形式为

combine-async-error([
	{
		func: requestAuthor,
		callback: () => {} // 提前为requestAuthor指定好的回调函数
	}
], {
	requestCallback: {
		failed: true // 指定了failed
	}
})

上述示例中,只有当requestAuthor请求函数出错时,才会执行该请求函数所指定好的callback回调,并且此回调函数会收到requestAuthor失败的原因

返回值

需要注意的是,combine-async-error不会抛出任何错误(除非你传递的类型参数不正确)

combineAsyncError的返回值

该返回值取决于是否指定了acc配置项 combineAsyncError的返回值有以下两种情况

  • undefined
  • Promise实例

请求结果的返回值

请求成功

当所有请求函数都执行成功时,收到的结果如下

// 标识每次请求的失败与否
const interface = [true, true, true]
{
    "result": [
        { "flag": true, "data": { "msg": "《三国演义》的作者是罗贯中" } },
        { "flag": true, "data": { "msg": "《三国演义》的价格是99元" } },
        { "flag": true, "data": { "msg": "《三国演义》的出版社是人民邮电出版社" } }
    ],
    "error": null
}

errornull,代表本次没有请求函数出现失败

result中存储着每次请求到的数据,flag标识当前请求是否成功,data.msg则为请求到的数据

某个请求函数失败

// 标识每次请求的失败与否
const interface = [true, false, true]
{
    "result": [
        { "flag": true, "data": { "msg": "《三国演义》的作者是罗贯中" } }
    ],
    "error": {
        "msg": "请求《三国演义》的【价格】时出错,你现在可以做出具体的操作了",
        "funcName": "requestPrice"
    }
}

当某个请求失败时,error中将包含该请求函数的失败原因名字

注意

请求结果({result: ..., error: ...})的返回形式,及如何返回,会受到配置项的影响

不足

如果你对combine-async-error有任何建议,欢迎反馈

期待你的最优解

// 修复了配置项失效的问题
// requestCallback
// all
// isCheckTypes