嵌套的异步方法怎么返回一个值?

2021-02-09 11:09:40 +08:00
 lbfeng

puppeteer 官方文档里的一段代码想改一下 https://pptr.dev/#?product=Puppeteer&version=v7.0.1&show=api-pagewaitforselectorselector-options

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  let currentURL;
  page
    .waitForSelector('img')
    .then(() => console.log('First URL with image: ' + currentURL));
  for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com']) {
    await page.goto(currentURL);
  }
  await browser.close();
})();

简单的 print 第一个有 img 的网站。想改成

const puppeteer = require('puppeteer');

const get_available_item = async (page) => {
  let currentURL;
  const urls = [
    'https://example.com',
    'https://example.com',
    'https://baidu.com'
  ]
  page.waitForSelector('img').then(
    () => {
      console.log('First URL with image: ' + currentURL)
    }
  );
  for (currentURL of urls) {
    await page.goto(currentURL, {waitUntil: 'load'});
  }
};

const main = async () => {
  const browser = await puppeteer.launch({
    headless: false,
    product: 'firefox',
    defaultViewport: { width: 1366, height: 768 }
  });
  
  const page = await browser.newPage();
  await get_available_item(page)
  await browser.close();
}

main()

想让get_available_item返回currentURL,试了一种用 callback 返回的方法

const puppeteer = require('puppeteer');

const get_available_item = async (page, callback) => {
  let currentURL;
  const urls = [
    'https://example.com',
    'https://example.com',
    'https://baidu.com'
  ]
  page.waitForSelector('img').then(
    () => {
      callback(currentURL)
    }
  );
  for (currentURL of urls) {
    await page.goto(currentURL, {waitUntil: 'load'});
  }
};

const main = async () => {
  let url
  const browser = await puppeteer.launch({
    headless: false,
    product: 'firefox',
    defaultViewport: { width: 1366, height: 768 }
  });
  
  const page = await browser.newPage();
  await get_available_item(page, (res) => {
  	url = res
  })
  console.log(`result is ${url}`)
  await browser.close();
}

main()

有比 callback 更简洁的方法么?

1827 次点击
所在节点    JavaScript
9 条回复
cyrbuzz
2021-02-09 11:29:39 +08:00
试试用订阅发布模型。

window.addEventListener('getWithImageUrl', (_url) => url = _url); window.dispatchEvent(new Event('getWithImage'))
azcvcza
2021-02-09 11:32:04 +08:00
能在你想返回的地方加点注释吗。。
musi
2021-02-09 11:45:49 +08:00
既然已经用 async 了,把 callback 改成 promise 后用 await
lzdyes
2021-02-09 12:10:51 +08:00
你都用 async await 了还不会包装个 Promise 吗,返回值 <string>Promise
lzdyes
2021-02-09 12:27:33 +08:00
const get_available_item = async (page: string):Promise<string> => {
return new Promise<string>( ( reject) =>{
// ...
reject(currentURL)
})
}

const currentURL = await get_available_item(page)
oxromantic
2021-02-09 12:47:20 +08:00
@lzdyes 为什么你第一个参数起名叫 reject ????
azcvcza
2021-02-09 13:48:12 +08:00
@oxromantic 实际上都是按参数位置调的,叫 reject 一样按 resolve 用,就是迷惑了点
lzdyes
2021-02-09 14:12:27 +08:00
啊哈,脑抽写错了··· 不过不影响···· lz 自己改成 resolve 吧
lbfeng
2021-02-10 03:15:21 +08:00
@cyrbuzz 这个真没想到。
@lzdyes 你这个可能不 work 。new Promise 里的 function 一般情况下是 sync function,但因为有 await 必须用 async 。

```javascript
const operation1 = Promise.resolve(5)
const operation2 = Promise.resolve(15)
const publishResult = () => Promise.reject(`Can't publish`)

let p = new Promise((resolve, reject) => {
(async () => {
try {
const op1 = await operation1;
const op2 = await operation2;

if (op2 == null) {
throw new Error('Validation error');
}

const res = op1 + op2;
const result = await publishResult(res);
resolve(result)
} catch (err) {
reject(err)
}
})()
});

(async () => {
await p;
})().catch(e => console.log("Caught: " + e));
```

这个例子 work,但有 anti pattern

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/752556

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX