【问题标题】:How to make an synchronous POST request in a for loop?如何在 for 循环中发出同步 POST 请求?
【发布时间】:2020-09-14 13:52:18
【问题描述】:

我有一组 URL,我将它们发送到后端以通过 Puppeteer 检索屏幕截图。在前端,我通过遍历数组并发送请求来发送 URL。由于 POST 请求是异步的,因此我将图像弄乱了。我怎样才能使图像按数组的顺序返回?

这是我的前端代码:

for (i = 0; i < array.length; i++) {
    var count = 0
    $.post("/api/screenshot", { url: array[i] })
      .done(res => {
        const { result } = res
        count++
        console.log(count)
        console.log(res)
        var img = document.createElement("img");
        img.src = "data:image/png;base64," + result;
        img.height = "500";
        var preview = document.getElementById("test");
        preview.appendChild(img);
        if (count == array.length) {
          $("#load-btn").hide()
          $("#ss-btn").show()
        }
      })
  }

我的后端代码:

app.post('/api/screenshot', async (req, res) => {
  const { url } = req.body

  try {
    let screenshot = await takeScreenshot(url)
    let img = screenshot.toString('base64')
    res.send({ result: img })
  } catch (e) {
    // catch errors and send error status
    console.log(e);
    res.sendStatus(500);
  }
});

async function takeScreenshot(url) {
  const browser = await puppeteer.launch({
    headless: true,
    args: ['--no-sandbox']
  });
  const page = await browser.newPage();
  await page.goto(url, { waitUntil: 'networkidle0' });
  await page.setViewport({
    width: 1400,
    height: 1000,
    deviceScaleFactor: 1,
  });
  const screenshot = await page.screenshot()

  await browser.close();
  return screenshot;
}

【问题讨论】:

  • 你可以尝试在$.post前加一个await
  • 或映射 $.post 承诺的数组并使用 Promise.all() 其结果将与 urls 的顺序相同
  • 使用 { async: true, url: array[i] } 或使用recursive async function
  • @NamNguyen async:true 是默认值,async:false 永远不应被使用,浏览器供应商已弃用

标签: javascript jquery node.js asynchronous puppeteer


【解决方案1】:

这可能会有所帮助:

let yourUrlArray=["url 1", "url 2","etc"]
await yourUrlArray.reduce(async(promise,url)=> 
   {
        await promise;
    // do your stuff with url
       $.post(url)
    },Promise.resolve())

这种方式reduce将等待直到$.post完成运行以解决数组中每个元素的promise

【讨论】:

  • 我无法想象这会像你想象的那样。
  • 你需要在reduce函数中返回promise
【解决方案2】:

这是一个想法:

var images = ['image1', 'images2']

function doNext(){
  var url = images.shift()
  if(url){
    $.post("/api/screenshot", { url })
      .done(res => {
        // do stuff here
        // keep calling doNext until images is empty
        doNext()
      })    
  }
}

doNext()

这避免了一些浏览器仍然存在的一些 es6 兼容性问题

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-06
    • 2018-11-13
    • 2017-03-17
    • 2018-06-11
    • 1970-01-01
    • 2016-11-13
    • 2016-04-09
    • 2019-02-24
    相关资源
    最近更新 更多