I am trying to build a simple directory tree with the Google Drive Javascript API. I suppose I should check for the folder existence and create it then add eventually its children. So I built these functions below:
function createFolder(name, parent) {
if (!parent) parent = 'root';
var fileMetadata = {
'name': name,
'mimeType': 'application/vnd.google-apps.folder',
'parent': parent
};
gapi.client.drive.files.create({
'resource': fileMetadata,
'fields': 'id'
}).then(function (res) {console.log(res); return res.result['id'];}, function (err) {console.log(err); return null;});
}
function getFolder(name, parent) {
if (!parent) parent = 'root';
gapi.client.drive.files.list({
'pageSize': 1,
'fields': "nextPageToken, files(id, name, mimeType, parents)",
'q': "mimeType='application/vnd.google-apps.folder' \
and '" + parent + "' in parents \
and name = '" + name + "'"
}).then(
function (res) {console.log(res); var ret = res.result.files.length > 0 ? res.result.files[0]['id'] : null; return ret;},
function (err) {console.log(err);return null;}
);
}
function checkPhrFolder() {
var phr = getFolder('Personal Health Record');
console.log('get folder: '+phr);
if (!phr) {
console.log('creating ...');
phr = createFolder('Personal Health Record');
}
}
This simply checks if my first dir exists and if not, creates it. The problem is that the calls are async (using "then promises") so the functions do not return anything (getFolder for example never returns the id of the folder), so I was wondering what is the correct way of creating recursively many folders given the nature of the async calls. Do I need to put a controller function that is always called and chose what to do next ?
Thank you !
In this case I found the new asynchronous javascript syntax easier to understand.
You are running the function checkPhrFolder
synchronously, while the other two functions, whose depend on the asynchronous api call, are waiting the promise to resolve in order to return a value. This will cause phr to be undefined when you evaluate it in the synchronous checkPhrFolder
execution.
Basically for this to work you should chain your promises resolution in order to use their return values correctly. The new javascript syntax although enables you to write asynchronous functions with fewer lines of code.
With the keywords async
and await
you can control the promises resolution flow, and basically wait the asynchronous function to return before making the proper assignment.
async function createFolder(name, parent) {
if (!parent) parent = 'root';
var fileMetadata = {
'name': name,
'mimeType': 'application/vnd.google-apps.folder',
'parent': parent
};
const res = await gapi.client.drive.files.create({
'resource': fileMetadata,
'fields': 'id'
});
return res.result['id'];
}
async function getFolder(name, parent) {
if (!parent) parent = 'root';
const res = await gapi.client.drive.files.list({
'pageSize': 1,
'fields': "nextPageToken, files(id, name, mimeType, parents)",
'q': "mimeType='application/vnd.google-apps.folder' \
and '" + parent + "' in parents \
and name = '" + name + "'"
});
return res.result.files.length > 0 ? res.result.files[0]['id'] : null;
}
async function checkPhrFolder() {
var phr = await getFolder('Personal Health Record');
console.log('get folder: '+phr);
if (!phr) {
console.log('creating ...');
phr = createFolder('Personal Health Record');
}
}
In this way your checPhrFolder
function will be almost as easy to read as before. When you will use the checkPhrFolder
function in a synchronous context you will be able to wrap its return value in the same then/catch
statement.