pFind

pFind

  • (predicate: AsyncPredicate) => async (collection: Collection) => Value | undefined
  1. One at a time, asynchronously find the first value that passes a condition

    const gt2 = async n => n > 2
    const findGt2 = pFind(gt2)
    
    await findGt2([1, 2, 3]) // is 3
    await findGt2([1, 2]) // is undefined
    const gt2 = async (n: number) => n > 2
    const findGt2 = pFind(gt2)
    
    await findGt2([1, 2, 3]) // is 3
    await findGt2([1, 2]) // is undefined
    
    const gt2 = async n => n > 2
    const findGt2 = pFind(gt2)
    
    await findGt2([1, 2, 3]) // is 3
    await findGt2([1, 2]) // is undefined
    const gt2 = async (n: number) => n > 2
    const findGt2 = pFind(gt2)
    
    await findGt2([1, 2, 3]) // is 3
    await findGt2([1, 2]) // is undefined
    
  2. Sometimes we want to asynchronously find a value that passes a condition. Below, we're running an online store. Customers have expressed confusion about discount codes being applied. Let's clarify by showing which item qualifies their order for a code.

    const mockStoreApi = {
      qualifiesForDiscount: async ({ code, item }) =>
        item === 'detergent' && code === 'soft',
    }
    
    const shoppingCart = ['broom', 'mop', 'detergent']
    const findQualifyingItem = pFind(mockStoreApi.qualifiesForDiscount)
    const itemCodeArgs = shoppingCart.map(item => ({ item, code: 'soft' }))
    const result = await findQualifyingItem(itemCodeArgs)
    
    if (result) {
      const { code, item } = result
      console.log(`code '${code}' applied because you bought ${item}`)
    }
    type ItemCode = {
      item: string
      code: string
    }
    
    const mockStoreApi = {
      qualifiesForDiscount: async ({ code, item }: ItemCode) =>
        item === 'detergent' && code === 'soft',
    }
    
    const shoppingCart = ['broom', 'mop', 'detergent']
    const findQualifyingItem = pFind(mockStoreApi.qualifiesForDiscount)<ItemCode[]>
    const itemCodeArgs = shoppingCart.map(item => ({ item, code: 'soft' }))
    const result = await findQualifyingItem(itemCodeArgs)
    
    if (result) {
      const { code, item } = result
      console.log(`code '${code}' applied because you bought ${item}`)
    }
    
    const mockStoreApi = {
      qualifiesForDiscount: async ({ code, item }) =>
        item === 'detergent' && code === 'soft',
    }
    
    const shoppingCart = ['broom', 'mop', 'detergent']
    const findQualifyingItem = pFind(
      mockStoreApi.qualifiesForDiscount
    )
    const itemCodeArgs = shoppingCart.map(item => ({
      item,
      code: 'soft',
    }))
    const result =
      await findQualifyingItem(itemCodeArgs)
    
    if (result) {
      const { code, item } = result
      console.log(
        `code '${code}' applied because you bought ${item}`
      )
    }
    type ItemCode = {
      item: string
      code: string
    }
    
    const mockStoreApi = {
      qualifiesForDiscount: async ({
        code,
        item,
      }: ItemCode) =>
        item === 'detergent' && code === 'soft',
    }
    
    const shoppingCart = ['broom', 'mop', 'detergent']
    const findQualifyingItem = pFind(
      mockStoreApi.qualifiesForDiscount
    )<ItemCode[]>
    const itemCodeArgs = shoppingCart.map(item => ({
      item,
      code: 'soft',
    }))
    const result =
      await findQualifyingItem(itemCodeArgs)
    
    if (result) {
      const { code, item } = result
      console.log(
        `code '${code}' applied because you bought ${item}`
      )
    }
    
  3. pFind awaits each item before moving onto the next. See async.detectLimit if you want to run more than one call at a time.

    const start = new Date().getTime()
    
    const gt2 = async n => {
      const msPassed = Date.now() - start
      console.log(`ms passed: ${msPassed}, for n = ${n}`)
    
      await pWaitMs(20)
      return n > 2
    }
    const findGt2 = pFind(gt2)
    
    await findGt2([1, 2, 3])
    const totalMsPassed = Date.now() - start
    console.log(`total ms passed: ${totalMsPassed}`)
    const start = new Date().getTime()
    
    const gt2 = async (n: number) => {
      const msPassed = Date.now() - start
      console.log(`ms passed: ${msPassed}, for n = ${n}`)
    
      await pWaitMs(20)
      return n > 2
    }
    const findGt2 = pFind(gt2)<number[]>
    
    await findGt2([1, 2, 3])
    const totalMsPassed = Date.now() - start
    console.log(`total ms passed: ${totalMsPassed}`)
    
    const start = new Date().getTime()
    
    const gt2 = async n => {
      const msPassed = Date.now() - start
      console.log(
        `ms passed: ${msPassed}, for n = ${n}`
      )
    
      await pWaitMs(20)
      return n > 2
    }
    const findGt2 = pFind(gt2)
    
    await findGt2([1, 2, 3])
    const totalMsPassed = Date.now() - start
    console.log(`total ms passed: ${totalMsPassed}`)
    const start = new Date().getTime()
    
    const gt2 = async (n: number) => {
      const msPassed = Date.now() - start
      console.log(
        `ms passed: ${msPassed}, for n = ${n}`
      )
    
      await pWaitMs(20)
      return n > 2
    }
    const findGt2 = pFind(gt2)<number[]>
    
    await findGt2([1, 2, 3])
    const totalMsPassed = Date.now() - start
    console.log(`total ms passed: ${totalMsPassed}`)