Node - ReferenceError: Promise is not defined - javascript

I am starting out with Node. Sorry for what probably is a stupid question.
Trying to understand why the below code throws an error: ReferenceError: Promise is not defined
allAccountFixtures: ['account-customer-joe', 'account-partner-sam', 'account-partner-jane', 'account-admin-jill'],
allProductFixtures: ['product-123', 'product-234', 'product-345', 'product-456'],
...
loadBasicFixtures: (Api) => {
return Promise.all([
Support.importRecords(Api.accountsAPI, Support.allAccountFixtures),
Support.importRecords(Api.productsAPI, Support.allProductFixtures)
]);
},
My APIs are defined elsewhere as:
this.accountsAPI = app.service('/api/accounts');
this.productsAPI = app.service('/api/products');
The import function is:
importRecords: (feathersService, fixtureNames) => {
// Wrap in an array if there's only one.
if (!(fixtureNames instanceof Array)) { fixtureNames = [fixtureNames]; }
// Create a separate promise for each JSON fixture to load the JSON from a
// file and send it to feathers.create(). Don't execute yet.
var promises = fixtureNames.map(fixtureName => {
var filePath = `test/fixtures/json/${fixtureName}.json`;
// console.log(`-> Loading JSON fixture: ${filePath}`);
return fs.readFileAsync(filePath, 'utf8')
.then((jsonString) => {
return JSON.parse(jsonString);
}).then((json) => {
return feathersService.create(json);
});
});
// Wrap all fixture loading promises inside a single outer promise that will
// fire when all of the child promises are complete.
return Promise.all(promises);
},
Don't know whether the supplied information is sufficient to advise what is happening. I looked up the concept of a "promise" and that's pretty much it. Perhaps you could point to the right direction. The documentation mentions resolve and reject.

I'll make my comment into an answer since it solved your issue.
Some older versions of node.js do not have promises built-in and to use promises with them requires loading a third party library that adds promise support.
If you upgrade to any 4.x version of node.js or newer, you will have promises built-in to node.js.

You need to import and require Promise
npm install promise --save
Then
var Promise = require('promise');

Related

Loop through AWS Lambda Nodejs SDK function

I'm new to Nodejs and having trouble understand this issue: I tried to run a describe function against an array, and the AWS function seems to run after the main function has finished.
Here's the main function: (loop thru a list of ACM ARNs and check the status)
var checkCertStatus = function(resolveObj){
var promise = new Promise(function(resolve, reject){
console.log('1');
var retObj='';
resolveObj.Items.forEach(function(element) {
var certDescribeParams = {
CertificateArn: element.sslCertId
};
console.log('2');
acm.describeCertificate(certDescribeParams, function(err, data) {
if(err) reject(new Error(err));
else {
console.log(data.Certificate.DomainName + ': ' + data.Certificate.Status);
retObj+=data;
}
});
});
console.log('3');
resolve(retObj);
return promise;
})
}
Based on the debug log, assuming there are 2 items need to be processed, what I got:
1
2
2
3
example.com: ISSUED
example2.com: ISSUED
Basically, I need to pass this result to the next function in the chain (with promise and stuff).
Welcome to Node.js! Speaking generally, it might be helpful to study up on the asynchronous programming style. In particular, you seem to be mixing Promises and callbacks, which may make this example more confusing than it needs to be. I suggest using the AWS SDK's built-in feature to convert responses to Promises.
The first thing I notice is that you are manually constructing a Promise with a resolve/reject function. This is often a red flag unless you are creating a library. Most other libraries support Promises which you can simply use and chain. (This includes AWS SDK, as mentioned above.)
The second thing I notice is that your checkCertStatus function does not return anything. It creates a Promise but does not return it at the end. Your return promise; line is actually inside the callback function used to create the Promise.
Personally, when working with Promises, I prefer to use the Bluebird library. It provides more fully-featured Promises than native, including methods such as map. Conveniently, the AWS SDK can be configured to work with an alternative Promise constructor via AWS.config.setPromisesDependency() as documented here.
To simplify your logic, you might try something along these lines (untested code):
const Promise = require('bluebird');
AWS.config.setPromisesDependency(Promise);
const checkCertStatus = (resolveObj) => {
const items = resolveObj.Items;
console.log(`Mapping ${items.length} item(s)`);
return Promise.resolve(items)
.map((item) => {
const certDescribeParams = {
CertificateArn: item.sslCertId,
};
console.log(`Calling describeCertificate for ${item.sslCertId}`);
return acm.describeCertificate(certDescribeParams)
.promise()
.then((data) => {
console.log(`${data.Certificate.DomainName}: ${data.Certificate.Status}`);
return data;
});
});
};
We're defining checkCertStatus as a function which takes in resolveObj and returns a Promise chain starting from resolveObj.Items. (I apologize if you are not yet familiar with Arrow Functions.) The first and only step in this chain is to map the items array to a new array of Promises returned from the acm.describeCertificate method. If any one of these individual Promises fails, the top-level Promise chain will reject as well. Otherwise, the top-level Promise chain will resolve to an array of the results. (Note that I included an inessential .then step just to log the individual results, but you could remove that clause entirely.)
Hope this helps, and I apologize if I left any mistakes in the code.

Add the result of a chained promise into promise.all()

I try construct a promise, named downloadTextPromise, to download a file and then in Promise.all() to read the file content.
However, I still cannot read the file content in Promise.all().then.
I suspect that downloadTextPromise is a two-step promise, so only the first step (HTTP GET) is pushed into promises array. But I have little idea how to fix it.
Any hint? any solution that works is welcoming, request-promise-native package is not compulsory.
My code is as below:
const request = require("request-promise-native");
let promises = [];
//put several promises into promises array;
.....
let downloadTextPromise = request.get("http://example.com/xyz.txt").pipe(fs.createWriteStream(`~/xyz.txt`));
promises.push(downloadTextPromise);
Promise.all(promises).then(() => {
//I need xyz.txt content at this stage, but it is not ready immediately.
}
Firstly, check if downloadTextPromise is actually a promise. The library's documentation doesn't mention how pipe works. If it returns a native promise, you can do console.log(downloadTextPromise instanceof Promise). Otherwise, you can try console.log(!!downloadTextPromise.then).
If it's a promise, then one possibility is that the promise is resolved synchronously after the the stream ends. The code to actually write the file is added to the message queue. In this case, you can fix it by doing:
Promise.all(promises).then(() => {
setTimeout(() => {
// Do stuff with xyz.txt
}, 0);
}
The issue is the writeStream part, so I should build a function returning correct promise.
I don't find the way to construct one returning a promise from request.get().pipe(), instead I use request.get().then() and fs.writeFile() as below.
However, Another problem appears from the new solution: This fs.writeFile works all OK for txt files; for mp3 or mp4, the function returns no error, but the file content is invalid for further processing in Promise.all().then().
function downloadTextPromise() {
return new Promise((resolve, reject) => {
rp.get("http://example.com/xyz.txt").then(data => {
fs.writeFile("./xyz.txt, data, err => {
if (err) reject(err);
resolve(true);
});
});
});
}

Promise.all(...).spread is not a function when running promises in parallel

I'm trying to run 2 promises in paralel with sequelize, and then render the results in a .ejs template, but I'm receiving this error:
Promise.all(...).spread is not a function
This is my code:
var environment_hash = req.session.passport.user.environment_hash;
var Template = require('../models/index').Template;
var List = require('../models/index').List;
var values = {
where: { environment_hash: environment_hash,
is_deleted: 0
}
};
template = Template.findAll(values);
list = List.findAll(values);
Promise.all([template,list]).spread(function(templates,lists) {
res.render('campaign/create.ejs', {
templates: templates,
lists: lists
});
});
How can I solve thhis?
I'll make my comment into an answer since it solved your issue.
.spread() is not a standard promise method. It is available in the Bluebird promise library. Your code you included does not show that. Three possible solutions:
Access array values directly
You can just use .then(results => {...}) and access the results as results[0] and results[1].
Include the Bluebird Promise library
You can include the Bluebird promise library so you have access to .spread().
var Promise = require('bluebird');
Use destructuring in the callback arguments
In the latest versions of nodejs, you could also use destructuring assignment which kind of removes the need for .spread() like this:
Promise.all([template,list]).then(function([templates,lists]) {
res.render('campaign/create.ejs', {templates, lists});
});
You can write it without non-standard Bluebird features and keep less dependencies as well.
Promise.all([template,list])
.then(function([templates,lists]) {
};
ES6 Destructuring assignment
Promise.all([
Promise.resolve(1),
Promise.resolve(2),
]).then(([one, two]) => console.log(one, two));
This is a Bluebird Promise feature and you can access it via Sequelize.Promise without installing Bluebird module itself
Sequelize.Promise.all(promises).spread(...)
I needed to install BlueBird.
npm install bluebird
Then:
var Promise = require("bluebird");

Angular 1.5 && Async/Await && jasmine tests

I already looked everywhere but could not find a solution yet for my particular case.
We are using angular 1.5 and a Karma/Jasmine setup for unit tests. In the initial source code, I used ES2017 async/await in the controller. That seemed to work fine as long as I added $apply of $digest manually at the end.
So for example:
async function loadData() {
try {
vm.isLoading = true;
vm.data = await DataService.getData();
$scope.$apply();
}
catch (ex) {
vm.isLoading = false;
}
}
To write an automated test for this particular function, I tried to mock DataService.getData with Jasmine's spyOn. So, I did something like this:
spyOn(DataService, 'getData').and.returnValue($q.when(fakeResult));
Adding the spy worked, but when running a test, the code seems to get struck and not resolve with fakeResult. I tried adding $digest/$apply in the tests itself but could not fix it. I also did a lot of research, but still have no clue.
Does somebody have a clue?
Edit: testing the same method with $q promises works fine, but I would really like to use async/await...
I don't know if your setup is similar, but in our environment I had to do a couple of things to get transpiled async/await statements to resolve in jasmine tests.
In our tests, I was trying to mock out services that would return promises. I found that returning $q.when didn't work. Instead, I had to return actual A+ standard Promises. My guess is that Angular's $q promises aren't fully complaint with the standard and wouldn't work as a substitute.
Note that since we use PhantomJS for our tests, I had to add polyfills to get those Promises.
Many times in my tests I would have to wrap some of the expect statements in a setTimeout block. Again, my assumption is that the promises need an additional "tick" to process.
So the reason why there is no result is because nothing after await is executed. I had a similar issue when I was testing async/await inside react components.
I found somewhere that a testing method for this is as follows:
You have to use something similar to https://www.npmjs.com/package/jasmine-async-suite - this is what I used. It is for asynchronous tests where you are expecting a promise.
There could be also an other problem, that after the promise is resolved, the test stops, because there is nothing to wait for :). It could be very tricky.
So you have to manually call the method, in your case DataService.getData(), and use the .then() method, where you can put your expect statements - because of this step, your test is waiting for resolving the promise.
Here is an example of my code (I am also using async functions in tests):
it.async('should call `mySpecialMethod`', async () => {
const arrayToResolve = [ { data: 'data' } ];
const SomeService = context.SomeService;
spyOn(props, 'mySpecialMethod');
spyOn(SomeService, 'myMethodReturningPromise');
.and.returnValue(Promise.resolve(arrayToResolve));
//the method `myMethodReturningPromise` is called in componentDidMount
const wrapper = mount(<MyReactComponent {...props} />, context);
expect(SomeService.myMethodReturningPromise).toHaveBeenCalled();
//now I am calling the method again
await SomeService.myMethodReturningPromise();
//`mySpecialMethod` is calling after the `await` in my code
expect(props.mySpecialMethod).toHaveBeenCalled();
//after that I am changing the state
expect(wrapper.state().arrayToResolve).toEqual(arrayToResolve);
});
I hope this helps you :)
You can use the library async-await-jasmine:
import * as angular from 'angular';
import 'angular-mocks';
import {yourModule} from "./your-module-path";
import {LoadDataService} from './load-data';
import {$it} from "async-await-jasmine";
import {IRootScopeService} from "angular";
describe('Calculator', () => {
let $httpBackend: angular.IHttpBackendService;
beforeEach(() => {
angular.mock.module(calculatorModule.name);
angular.mock.inject((_$httpBackend_) => {
$httpBackend = _$httpBackend_;
});
});
$it('should loadData', async () => {
$httpBackend.when('GET', '/loadData').respond('{"value": 5}');
let sum = loadData(1, 4);
$httpBackend.flush();
expect(await sum).toBe(10);
});
});

Chaining Requests using BlueBird/ Request-Promise

I'm using the request-promise module and have found no mention of how to chain requests. I'm currently following their syntax of:
request({options})
.then(function(result){...})
.catch(function(error){...})
However I want to be able to use Promise.all and try to make multiple calls at the same time and wait for them to all resolve and then proceed with other calls. For example I want to:
Make a call to one app creating a User.
AT THE SAME TIME, make a call creating an Address.
Promise.all([UserCall, AddressCall]).then({function to deal with results])?
Also I have been working with my function in module.exports = {...}. Does this require me to be outside of exports and have them declare as separate variables?
From what I understand its seems as if I have to do something like:
var UserCall = function(req,res){
return new Promise(function (resolve, reject){
request({options})? //To make the call to create a new user?
// Then something with resolve and reject
Any help is much appreciated. I think I may be mixing up basic BlueBird concepts and trying to use them with request-promise.
Here you go:
var BPromise = require('bluebird');
var rp = require('request-promise');
BPromise.all([
rp(optionsForRequest1),
rp(optionsForRequest2)
])
.spread(function (responseRequest1, responseRequest2) {
// Proceed with other calls...
})
.catch(function (err) {
// Will be called if at least one request fails.
});
Like you said, you can accomplish this using the all API.
Refer to the documentation here: http://bluebirdjs.com/docs/api/promise.all.html
Example:
var self = this;
return new Promise(function(resolve) {
Promise.all([self.createUser, self.createAddress])done(
// code path when all promises are completed
// OR should any 1 promise return with reject()
function() { resolve(); }
);
})
As noted in the code, the .all() callback code path will get called as well when any 1 of the defined promise in promises gets rejected.

Categories

Resources