【问题标题】:JS array.map with costly async function具有昂贵异步功能的 JS array.map
【发布时间】:2021-03-19 14:57:35
【问题描述】:

我有一组用户。我需要在每个user.id 上调用“costlyEncryptionFunction”,但我不想在同一个user.id 上多次调用“costlyEncryptionFunction”。

这是一个工作示例:

const costlyEncryptionFunction = async (id) => {
  return new Promise((res) => {
    setTimeout(() => {
      res(id + 1000)
    }, 1000)
  })
}  

let users = [
  {id: 1, item: 1},
  {id: 1, item: 2},
  {id: 2, item: 5},
  {id: 2, item: 6}
]

let currentUserId
users.map(async (user) => {

  let encryptedUserId
  if(!currentUserId || currentUserId != user.id){
    currentUserId = user.id
    encryptedUserId = await costlyEncryptionFunction(currentUserId)
  }

  if(encryptedUserId){
    console.log(`inside: ${encryptedUserId} ${user.item} ... do more stuff` )
  }
})

输出读取

inside: 1001 1 ... do more stuff
inside: 1002 5 ... do more stuff

我正在尝试读取我的输出:

inside: 1001 1 ... do more stuff
inside: 1001 2 ... do more stuff
inside: 1002 5 ... do more stuff
inside: 1002 6 ... do more stuff

除了调用“costlyEncryptionFunction”并多次重复相同的userId 之外,有没有人对此有解决方案?

【问题讨论】:

  • 记忆函数?

标签: javascript arrays async-await


【解决方案1】:

最基本的方法是使用一个对象作为缓存:

const cache = {};

const costlyEncryptionFunction = async (id) => {
    const existing = cache[id];
    if (existing) return Promise.resolve(existing);
    
    return new Promise((res) => {
        setTimeout(() => {
            const encrypted = id + 1000;
            cache[id] = encrypted;
            res(encrypted);
        }, 1000)
    })
}

let users = [
    { id: 1, item: 1 },
    { id: 1, item: 2 },
    { id: 2, item: 5 },
    { id: 2, item: 6 }
]

let currentUserId
users.map(async (user) => {

    let encryptedUserId
    if (!currentUserId || currentUserId != user.id) {
        currentUserId = user.id
        encryptedUserId = await costlyEncryptionFunction(currentUserId)
    }

    if (encryptedUserId) {
        console.log(`inside: ${encryptedUserId} ${user.item} ... do more stuff`)
    }
})

如果你的目标环境支持,你可以使用Map:

const cache = new Map();

const costlyEncryptionFunction = async (id) => {
    const existing = cache.has(id) ? cache.get(id) : undefined;
    if (existing) return Promise.resolve(existing);

    return new Promise((res) => {
        setTimeout(() => {
            const encrypted = id + 1000;
            cache.set(id, encrypted) = encrypted;
            res(encrypted);
        }, 1000)
    })
}

let users = [
    { id: 1, item: 1 },
    { id: 1, item: 2 },
    { id: 2, item: 5 },
    { id: 2, item: 6 }
]

let currentUserId
users.map(async (user) => {

    let encryptedUserId
    if (!currentUserId || currentUserId != user.id) {
        currentUserId = user.id
        encryptedUserId = await costlyEncryptionFunction(currentUserId)
    }

    if (encryptedUserId) {
        console.log(`inside: ${encryptedUserId} ${user.item} ... do more stuff`)
    }
})

这或多或少是实用程序库通过其 memoize 方法在后台所做的事情,尽管它们通常提供诸如多个参数之类的功能,这会使实现有点复杂。

【讨论】:

  • "costlyEncryptionFunction" 显然不是真正的加密功能......但是,这个想法会奏效。我将在加密函数周围放置一个包装函数。
【解决方案2】:

假设你使用的是 Node.js,你可以使用 ramda 包来记忆函数

const {identity, memoizeWith} = require('ramda');

const costlyEncryptionFunction = async (id) => {
  return new Promise((res) => {
    setTimeout(() => {
      res(id + 1000)
    }, 1000)
  })
}  

const memoizedCostlyFunction = (identity, costlyEncryptionFunction)

let users = [
  {id: 1, item: 1},
  {id: 1, item: 2},
  {id: 2, item: 5},
  {id: 2, item: 6}
]

let currentUserId
users.map(async (user) => {

  let encryptedUserId
  if(true ){
    currentUserId = user.id
    // encryptedUserId = await costlyEncryptionFunction(currentUserId)
    encryptedUserId = await memoizedCostlyFunction(currentUserId)
  }

  if(encryptedUserId){
    console.log(`inside: ${encryptedUserId} ${user.item} ... do more stuff` )
  }
})

【讨论】:

    猜你喜欢
    • 2019-12-10
    • 1970-01-01
    • 2016-01-31
    • 1970-01-01
    • 1970-01-01
    • 2022-08-06
    • 1970-01-01
    • 1970-01-01
    • 2011-12-06
    相关资源
    最近更新 更多