【问题标题】:Use Promise.all to expedite the excution of one asynced and one synced tasks - async await syntax使用 Promise.all 加速执行一个同步任务和一个同步任务 - async await 语法
【发布时间】:2022-12-09 02:03:08
【问题描述】:

假设我有三个功能:

异步函数 - asyncF() - 例如,它调用 REST API。

同步功能sync()

执行器函数 exec() 会尽快调用它们,最好是并行调用。

我希望使用“Async-await”语法编写exec(),而不使用“Callbacks”或“Promises”语法。

把它写成:

async exec(){
const [res1, res2]= await Promise.all([asyncF(), sync()])
...
}

有没有更好的办法?

【问题讨论】:

  • JavaScript 只在一个线程中工作,所以没有什么是真正并行的。但是Promise.all这里应该没问题
  • 这是没有意义的。它只是添加了额外的语法而没有任何加速。事实上,它可能有点慢,因为你必须分配和 GC 额外的数组,加上来自 Promise.all 的开销。只需在不同的行上运行同步代码和异步代码,这将实现代码可能实现的所有并行性。
  • @ggorlen 不是真的,Promise.all 遍历参数所以它就像一个映射循环但更短
  • @Konrad 我不知道你的意思。在同步功能上使用Promise.all() 是如何实现的?

标签: javascript asynchronous async-await


【解决方案1】:
const p = asyncF();
const syncResult = sync();
const asyncResult = await p;

启动异步任务,然后运行同步功能,然后等待承诺解决。

如果同步任务需要更长的时间,就不会有额外的等待异步任务,因为承诺已经解决:

function sync() {
  const end = new Date();
  end.setSeconds(end.getSeconds() + 3);
  //loop for 3 seconds
  for (let now = new Date(); now < end; now = new Date());
  
  return 2;
}

function asyncF() {
  //after 1 seconds return the value 40
  return new Promise(resolve => setTimeout(resolve, 1000, 40));
}

async function exec(){
  const p = asyncF();
  const syncResult = sync();
  const asyncResult = await p;
  
  return syncResult + asyncResult;
}

const start = new Date();
exec().then(result => {
  console.log(`result was ${result}; it took ${new Date() - start}ms`)
})

如果异步任务花费的时间更长,则需要额外等待 promise 解决:

function sync() {
  //return immediately
  return 2;
}

function asyncF() {
  //after 3 seconds return the value 40
  return new Promise(resolve => setTimeout(resolve, 3000, 40));
}

async function exec(){
  const p = asyncF();
  const syncResult = sync();
  const asyncResult = await p;
  
  return syncResult + asyncResult;
}

const start = new Date();
exec().then(result => {
  console.log(`result was ${result}; it took ${new Date() - start}ms`)
})

当然,这假定异步任务是正确异步的。异步函数仍将同步执行,直到它到达 await 或结束。

请注意,如果存在风险,仍应处理异步拒绝。 await p 应在 try/catch 中或附加 .catch() 处理程序。

【讨论】:

    【解决方案2】:

    你不能真正并行运行两件事

    这也取决于你的异步函数是如何工作的,这里的异步函数将阻塞整个线程几乎一秒钟:

    exec()
    
    async function exec() {
      const startTime = Date.now()
      const [res1, res2] = await Promise.all([asyncF(), sync()])
      console.log('finished', Date.now() - startTime, 'ms')
    }
    
    function asyncF() {
      console.log('start async')
      return Promise.resolve().then(() => {
        let i = 100000000;
        let x = 0
        while (i--) {
          x += Math.random()
        }
        return 'async'
      })
    }
    
    function sync() {
      console.log('start sync')
      return 'sync'
    }

    关于评论中的问题:

    Promise.all在这里真正做的是替换map函数

    exec()
    
    async function exec() {
      const values = await Promise.all([sync(), sync(), sync()])
      console.log(values)
      
      const values2 = [sync, sync, sync].map(fn => fn())
      console.log(values2)
    }
    
    function sync() {
      return Math.random()
    }

    这个会比较好吗?不

    它更快吗?也没有

    【讨论】:

    • “你不能真正并行运行两件事”——你当然可以。这就是异步代码的意义所在。
    • JavaScript 会暂时停止一部分代码的执行,以处理另一部分代码。这不是平行的。肯定是异步的,但不是并行的
    • 也许您只是指同步代码,但您绝对可以并行运行多个异步调用,例如Promise.all([fetch(), fetch(), fetch()])。如果不是这个,你所说的并行是什么意思?此处显示的“异步”代码实际上并不是异步的。这是一个阻塞的繁忙循环,而不是网络或子进程调用,因此异步是没有意义的。几乎可以肯定,这不是 OP 的用例。
    • 当您调用 fetch 时,它是处理并行内容的浏览器。当响应返回时,微任务队列在单个共享线程中处理响应。我的代码是async 它只是不并行
    猜你喜欢
    • 2014-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-30
    • 2020-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多