My action in the background is to access the site and take information from there, the problem is that the code continues before the information is received.
Attached is a code that shows the problem:
background.js :
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
fetch(request.input, request.init).then(function(response) {
return response.text().then(function(text) {
sendResponse([{
body: text,
status: response.status,
statusText: response.statusText,
}, null]);
});
}, function(error) {
sendResponse([null, error]);
});
return true;
});
actions.js : after editing
const validateWord = async word => {
const input = "https://milog.co.il/" + word;
await new Promise(resolve => {
chrome.runtime.sendMessage({ input }, messageResponse => {
const [response, error] = messageResponse;
const parser = new DOMParser();
const html = parser.parseFromString(response.body, 'text/html');
const element = html.querySelector('.sr_e_txt');
console.log("aaa")
resolve(element?.innerText !== '');
});
});
};
validateWord("word")
.then(data => console.log(data))
.catch(reason => console.log(reason.message))
it prints aaa -> bbb -> word..
I want the "word" printed first and "aaa" wait for it to finish.
Thank you.
you can't use both a callback in a chrome method and await on the returned value because when a callback is used the method won't return a Promise.
bug in Chrome before 99: sendMessage doesn't return a Promise so you can't await it.
Fixed in Chrome 99.
So, in earlier versions of Chrome you can promisify the API:
promisifyApi(chrome.runtime, 'sendMessage');
(async () => {
const res = await chrome.runtime.sendMessage({ input });
console.log(res);
})();
function promisifyApi(thisArg, name) {
const fn = thisArg[name];
const localStack = new Error('Before calling ' + name);
thisArg[name] = (...args) => new Promise((resolve, reject) => {
fn(...args, result => {
let err = chrome.runtime.lastError;
if (err) {
err = new Error(err.message);
err.stack += '\n' + localStack.stack;
reject(err);
} else {
resolve(result);
}
});
});
}
...or use a callback:
chrome.runtime.sendMessage({ input }, res => {
// process `res` here
});
Related
Hi guys, I'm newbie in node.js. I have function, that leads the dialogue with user in console. In newSwagger function I call the bumpDiff function, that shows changes between 2 files.
async function bumpDiff = () => {
exec('bump diff swagger.json newSwagger.json', (err, output) => {
// once the command has completed, the callback function is called
if (err) {
// log and return if we encounter an error
console.error("could not execute command: ", err)
return
}
// log the output received from the command
console.log("Output: \n", output)
})
};
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const question = (str) => new Promise(resolve => rl.question(str, resolve));
const steps = {
start: async () => {
return steps.changeSwagger();
},
changeSwagger: async () => {
const addSwagger = await request();
console.log('success');
const changeSwagger = await question("Would you like to check changes in swagger? Please type yes/no: ");
if (changeSwagger === 'yes') { return steps.newSwagger(); }
if (changeSwagger === 'no') { return steps.oldSwagger(); }
return steps.end();
},
newSwagger: async () => {
console.log('showing changes');
const diff = await bumpDiff();
const ask = await question('Would you like to change swagger? Please type yes/no: ');
if (ask === 'yes') { return steps.changing(); }
if (ask === 'no') { return steps.end(); }
},
changing: async () => {
const rebuildSwagger = await SwaggerNew();
console.log('swagger changed successfully');
return steps.end();
},
oldSwagger: async () => {
console.log('No worries, have a nice day');
return steps.end();
},
end: async () => {
rl.close();
},
};
steps.start();
The problems is: when bumpDiff is starting, next readline
'Would you like to change swagger? Please type yes/no: '
come faster, then changes appeares. I guess I'm missing something about promises, can you help me find the mistake please.
P.S. all other functions, like 'request' and 'SwaggerNew' are async.
You are mixing two "styles" the callback approach in the "exec" function and you are trying to await that bumpDiff that is not returning a Promise (async/await approach), take a look to utils.Promisify helper function.
From NodeJS docs:
const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);
async function lsExample() {
const { stdout, stderr } = await exec('ls');
console.log('stdout:', stdout);
console.error('stderr:', stderr);
}
lsExample();
You need to turn the callback style exec call into a promise so that await bumpDiff() can work properly.
async function bumpDiff = () => {
return new Promise((resolve, reject) => {
exec('bump diff swagger.json newSwagger.json', (err, output) => {
if (err) {
console.error("could not execute command: ", err)
reject(err)
} else {
console.log("Output: \n", output)
resolve(output)
}
})
})
};
I searched about this but I didn't find anything specific for what I need. If there is one, please, share here.
I am creating the video upload Api using Vimeo . Problem is, the editor returns the message "'await' has no effect on the type of this expression". And the app indeed crashes since there is no data yet.
const videoUpload = async (data) => {
let file_name = data.path;
await client.upload(
file_name,
{
name: "Untitled",
description: "The description goes here.",
},
(uri) => {
client.request(uri + "?fields=link", function (error, body, statusCode, headers) {
if (error) {
console.log("There was an error making the request.");
console.log("Server reported: " + error);
}
data.link = body.link;
});
},
(bytes_uploaded, bytes_total) => {
var percentage = ((bytes_uploaded / bytes_total) * 100).toFixed(2);
console.log(bytes_uploaded, bytes_total, percentage + "%");
},
(error) => {
console.log("Failed because: " + error);
}
);
return data;
};
The upload method does not return a promise, but instead uses a callback pattern. This means upload returns before any of the callback arguments are called. Using await on that will not have the desired effect, as upload just returned undefined, and await will just wrap that as a promise and see it is already resolved. The same problem happens again with the call to request.
In such situations you can check whether the API provides a promise-based alternative, but I couldn't find it. So then you can promisify the relevant methods yourself. For instance, like this:
// create an promise-enabled alternative for client API
const promiseClient = {
upload(fileName, options, progressCallback) {
return new Promise((resolve, reject) =>
client.upload(fileName, options, resolve, progressCallback, reject)
);
},
request(uri) {
return new Promise((resolve, reject) =>
client.request(uri, (error, body, statusCode, headers) =>
error ? reject(error) : resolve({body, statusCode, headers})
)
);
}
};
const videoUpload = async (data) => {
const file_name = data.path;
try {
const uri = await promiseClient.upload(
file_name,
{
name: "Untitled",
description: "The description goes here.",
},
(bytes_uploaded, bytes_total) => {
const percentage = ((bytes_uploaded / bytes_total) * 100).toFixed(2);
console.log(bytes_uploaded, bytes_total, percentage + "%");
}
);
const {body} = await promiseClient.request(uri + "?fields=link");
data.link = body.link;
return data;
} catch (error) {
console.log("Video upload failed because: ", error);
throw error; // Maybe you want to cascade the error to the caller...
}
};
I have a lambda function with the structure below,
It used to work in older versions of nodejs but it doesn't work with the newer versions.
I know my code structure is quite messy and wrong but I can't get my head around it. I'm trying to use Promise.all but I'm obviously doing something wrong cause it's not getting executed at all.
By the way, I'm not getting any errors. The promise.all method never gets executed.
let AWS = require('aws-sdk');
exports.handler = async(event, context, callback) => {
let result = {};
try {
result = await getOrder(sql, 0);
result.map(
(dataField) => {
});
}
catch (error) {
console.log(error);
callback(error);
}
var today_result = [];
const groupKey = i => i.user_id + '_' + i.when;
const counts = _.countBy(followingsIDs, groupKey);
const isMulti = i => counts[groupKey(i)] > 1;
const multiPropkey = i => ({ multiplekey: isMulti(i) ? groupKey(i) : groupKey(i) });
const multiProp = i => ({ multiple: isMulti(i) ? counts[groupKey(i)] : 1 });
const updated = _.map(followingsIDs, i => _.extend(i, multiProp(i), multiPropkey(i)));
const uniqResult = _.uniq(updated, function(d) { return d.multiplekey });
// Doesn’t execute from here —>
await Promise.all(uniqResult.map(async(dataField) => {
console.log("test_");
dosomething()
if (true) {
let sql = `INSERT INTO ….`
result = await getOrder(sql, 0);
try {
const data = await sns.publish(params).promise();
}
catch (e) {
console.log(e.stack);
response.result = 'Error';
}
}
}));
// Till here <----
callback(null, uniqResult);
};
let getOrder = async(sql, params) => {
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if (err) throw err;
connection.query(sql, params, (err, results) => {
if (err) {
reject(err);
}
// console.log("-----Query Done!");
connection.release();
// console.log("-----Data: ", results);
resolve(results);
});
});
});
};
What are you awaiting to? The uniqResult is just declared as an empty array. Immediately after that you pass it to Promise.all. You need to fill it with Promises and then pass it to Promise.all.
Hello I am new working with asynchronous calls I hope you can help me.
I have a .then chain where I want to call in the middle of the chain a function that returns a promise but it happens to me that the chain does not wait for it to have the result of the promise function and continues without waiting
var User = require('../models/user_model');
var mapbox = require('./helper/request_api_mapbox');
findOne_mapbox: (req, res) => {
User.findById(req.params.id)
.then(user => {
...
return user.address;
})
.then(function (adress_to_mapbox)
{
// mapbox.connect_mapbox returns a promise
mapbox.connect_mapbox(adress_to_mapbox)
.then(mapbox_coordinates => {
//inside this console.log is not read it
console.log("2 then mapbox_coordinates ", mapbox_coordinates)
return Promise.resolve(body);
})
})
.then( mapbox_coordinates => {
// in this console.log mapbox_coordinates returns undefined
console.log("last promise mapbox_coordinates",
mapbox_coordinates)
// I want to return mapbox_coordinates
return res.status(200).send({
"response": "I only receive this string "
});
})
}
the promise function is:
'use strict'
const rp = require('request-promise');
const access_token_mapbox = 'bla bla bla private';
function connect_mapbox(adress_to_mapbox) {
return new Promise((resolve, reject) => {
var options = {
method: 'GET',
uri: 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + adress_to_mapbox + '.json?access_token=' + access_token_mapbox,
json: true // Automatically stringifies the body to JSON
};
rp(options)
.then(body => {
if (body.hasOwnProperty('errcode') && body.errcode != 0) {
return Promise.reject(body);
}
console.log("inside connect_mapbox function on mapbox_model 2", body)
return Promise.resolve(body);
})
.catch(err => {
debug(err);
return Promise.reject(err);
})
})
}
module.exports = { connect_mapbox };
Inside the promise function I can see in my console.log that it makes the api call properly and the response body is ok.
I am starting in the programming, I solved the problem in the following way although I don't know if it is the most correct
I solved it by converting the connect_mapbox promise function to async await and the .then chain to async await like so:
'use strict'
const rp = require('request-promise');
const access_token_mapbox = 'bla bla bla private';
async function connect_mapbox(adress_to_mapbox) {
try {
var options = {
method: 'GET',
uri: 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + adress_to_mapbox + '.json?access_token=' + access_token_mapbox,
json: true // Automatically stringifies the body to JSON
};
let response = await rp(options);
console.log("inside connect_mapbox function on mapbox_model", response)
if (response.hasOwnProperty('errcode') && body.errcode != 0) {
return Promise.reject(response);
}
return Promise.resolve(response);
}catch(error) {
return Promise.reject(error);
}
}
module.exports = { connect_mapbox };
And the .then chain like
var User = require('../models/user_model');
var mapbox = require('./helper/request_api_mapbox');
findOne_mapbox: (req, res) => {
User.findById(req.params.id)
.then(user => {
...
return user.address;
})
.then(async function (adress_to_mapbox)
{
console.log("adress_to_mapbox thit could be deleted", adress_to_mapbox)
let mapbox_response = await mapbox.connect_mapbox(adress_to_mapbox)
console.log("async mapbox_response", mapbox_response)
return res.status(200).send({
mapbox_response
});
})
...
}
I want to do make the same api call as made in this postman photo below :
postman
I have already tried the following code but it only returns some html not the desired response
async function vendor_info() {
const options = {
uri: 'http://**.**.**.**/vendor/:username/pj1527',
json: true,
method: 'GET'
};
let vendor_info = undefined;
await requestPromise(options)
.then((body) => {
// err_token = 0;
vendor_info = body[0];
console.log(body);
// console.log(body[0]);
})
.catch(err => {
vendor_info = undefined;
// err_token = 1;
// console.log(err);
});
return vendor_info;
}
EDIT
It's working now, actually the url should be 'http://.../vendor//pj1527' in the request.
If you are using async await then there is no need to use then and catch blocks, Try like this:
async function vendor_info() {
try {
const options = {
uri: 'http://**.**.**.**/vendor/:username/pj1527',
json: true,
method: 'GET'
};
const vendor_info = await requestPromise(options);
console.log('vendor_info: => ', vendor_info);
return vendor_info;
} catch (err) {
console.log('Error: => ', err);
return err;
}
}
Hope this helps :)