Callback или Promise как правильно дождаться результата функции?
Мне нужно дождаться чтобы result был не null Я использую цикл for но хочу сделать это как-то лучше, как это можно сделать через промис и есть ли в этом смысл? Подскажи варианты. Полученый результат использую в другой функции.
const fetch = require('node-fetch')
getLinkToConfirmRegistration: async (email, typeLink = "reg", page) => {
const partsEmail = email.split("@");
let result;
for (const i of [1, 2, 3, 4, 5]) {
await page.waitForTimeout(1000);
result = await fetch(
`https://www.1secmail.com/api/v1/?action=getMessages&login=${partsEmail[0]}&domain=${partsEmail[1]}`
).then((res) => res.json());
if (result !== null) {
break;
} else if (i === 5 && result === null) {
throw new Error(`Emails are not sent`);
}
}
try {
const link = await fetch(
`https://www.1secmail.com/api/v1/?action=readMessage&login=${partsEmail[0]}&domain=${partsEmail[1]}&id=${result[0].id}`
).then((res) => res.json());
if (typeLink === "template") {
return link;
}
if (typeLink !== "reg") {
const re = /(https?:\/\/\S+\w)/g;
const nameList = link.textBody.match(re);
return nameList[0];
}
const words = link.body.match(/(".*?")/);
const clearLink = words[0].replace(/"/g, "");
return clearLink;
} catch (error) {
console.error(error);
return null;
}
},
Ответы (1 шт):
Автор решения: nörbörnën
→ Ссылка
Для доступа к api бы сделал "клиента" в котором бы инкапсулировал всё необходимое для общения с сервисом:
// @ts-check
const { default: fetch } = require('node-fetch');
const { URL, URLSearchParams } = require('url');
const sleep = (timeout = 1000) => new Promise((r) => setTimeout(r, timeout));
/**
* @param {string} email
* @param {'template' | 'reg'} [typeLink='reg']
*/
async function getLinkToConfirmRegistration(email, typeLink = 'reg') {
const client = new OneSecMailClient(email);
let count = 100;
let messages;
while (count--) {
try {
messages = await client.action('getMessages');
if (messages && Array.isArray(messages) && messages.length > 0) {
break;
}
await sleep();
} catch (err) {
console.error(err);
}
}
let lastMessage;
if (messages && Array.isArray(messages) && messages.length > 0) {
lastMessage = await client.action('readMessage', { id: messages[0].id });
}
if (!lastMessage) {
throw new Error(`Emails are not sent`);
}
console.log(lastMessage.textBody);
}
class OneSecMailClient {
#endpoint = 'https://www.1secmail.com/api/v1/';
#login
#domain
/**
* @param {string} email
* @memberof OneSecMailClient
*/
constructor(email) {
[ this.#login, this.#domain ] = email.split('@');
}
async action(actionName, param = {}) {
const url = new URL(this.#endpoint);
url.search = new URLSearchParams({
action: actionName,
login: this.#login,
domain: this.#domain,
...param
}).toString();
const res = await fetch(
url.toString(),
{
headers: { 'Content-Type': 'application/json' },
}
);
if (!res.ok) {
throw new Error(res.statusText || `Status: ${res.status}`);
}
return res.json();
}
}
(async () => {
const email = '[email protected]';
await getLinkToConfirmRegistration(email, 'reg');
})();
Этот код можно проверить, запустив его и отправив письмо на указанный email:
mail -s 'subject' [email protected] <<< 'testing message body'
Я люблю использовать библиотеку p-retry для организации чего-то асинхронного и повторяемого, - она сделает наш код ещё нагляднее:
// @ts-check
const pRetry = require('p-retry');
const { default: fetch } = require('node-fetch');
const { URL, URLSearchParams } = require('url');
const sleep = (timeout = 1000) => new Promise((r) => setTimeout(r, timeout));
/**
* @param {string} email
* @param {'template' | 'reg'} [typeLink='reg']
*/
async function getLinkToConfirmRegistration(email, typeLink = 'reg') {
const client = new OneSecMailClient(email);
const messages = await pRetry(
async () => {
const list = await client.action('getMessages');
return Array.isArray(list) && list.length > 0 ? list : Promise.reject(new Error('Emails are not sent'));
},
{
retries: 100,
factor: 1
}
);
const lastMessage = await client.action('readMessage', { id: messages[0].id });
console.log(lastMessage.textBody);
}
class OneSecMailClient {
#endpoint = 'https://www.1secmail.com/api/v1/';
#login
#domain
/**
* @param {string} email
* @memberof OneSecMailClient
*/
constructor(email) {
[ this.#login, this.#domain ] = email.split('@');
}
async action(actionName, param = {}) {
const url = new URL(this.#endpoint);
url.search = new URLSearchParams({
action: actionName,
login: this.#login,
domain: this.#domain,
...param
}).toString();
const res = await fetch(
url.toString(),
{
headers: { 'Content-Type': 'application/json' },
}
);
if (!res.ok) {
throw new Error(res.statusText || `Status: ${res.status}`);
}
return res.json();
}
}
(async () => {
const email = '[email protected]';
await getLinkToConfirmRegistration(email, 'reg');
})();