Revert Promises in file API to callbacks.

Promises do not seem reliable as they are in Chrome 34. Rather than
continue to implement hacks that can work around these problems, let's
just go back to callbacks. Maybe we don't need to be on the cutting edge
_all_ the time.
This commit is contained in:
Thomas Wilburn 2014-05-04 02:09:19 -07:00
parent a30bb4687e
commit 12870d3b1d
7 changed files with 89 additions and 121 deletions

View file

@ -21,7 +21,7 @@ define([
if (window.launchData) {
window.launchData.forEach(function(file) {
var f = new File(file.entry);
f.read().then(function(contents) {
f.read(function(err, contents) {
sessions.addFile(contents, f);
}, dialog);
});
@ -37,7 +37,7 @@ define([
//files get opened in a tab
if (entry.isFile) {
var f = new File(entry);
return f.read().then(function(data) {
return f.read(function(err, data) {
sessions.addFile(data, f);
}, dialog);
//directories get added to project
@ -74,7 +74,7 @@ define([
}
files.map(function(entry) {
var f = new File(entry);
return f.read().then(function(data) {
return f.read(function(err, data) {
sessions.addFile(data, f);
}, dialog);
});
@ -103,12 +103,12 @@ define([
command.on("session:revert-file", function(c) {
var tab = sessions.getCurrent();
if (!tab.file) return;
tab.file.read().then(function(data) {
tab.file.read(function(err, data) {
tab.setValue(data);
tab.modified = false;
tab.modifiedAt = new Date();
sessions.renderTabs();
c();
if (c) c();
});
});
@ -166,8 +166,10 @@ define([
command.on("session:insert-from-file", function(c) {
var f = new File();
f.open().then(f.read.bind(f)).then(function(text) {
editor.execCommand("insertstring", text);
f.open(function() {
f.read(function(err, text) {
editor.execCommand("insertstring", text);
});
});
});
@ -185,20 +187,18 @@ define([
data.retained,
function(id, i, c) {
var file = new File();
file
.restore(id)
.then(function() {
return file.read();
})
.then(function(data) {
file.restore(id, function() {
file.read(function(err, data) {
if (err) {
failures.push(id);
return c(null);
}
c({
value: data,
file: file
});
}, function(err) {
failures.push(id);
c(null);
});
});
},
function(restored) {
restored = restored.filter(function(d) { return d });
@ -222,19 +222,16 @@ define([
var reset = function() {
var tabs = sessions.getAllTabs();
var virtuals = [];
tabs.forEach(function(tab) {
if (tab.file && tab.file.virtual) {
var v = tab.file.read().then(function(data) {
virtuals++;
tab.file.read(function(err, data) {
tab.setValue(data);
tab.modified = false;
session.renderTabs();
});
virtuals.push(v);
}
});
Promise.all(virtuals).then(function() {
setTimeout(sessions.renderTabs, 10);
});
};
command.on("init:startup", init);

View file

@ -16,20 +16,6 @@ require([
"storage/syncfile"
], function(command, Settings, dialog, sessions, M) {
//Promises appear to be buggy during startup, but resolving one will fix it
//Rinse and repeat until init:complete fires
//TODO: remove once we can, this is stupid
var promiseBug = false;
command.on("init:complete", function() {
promiseBug = true;
});
var cycle = function() {
new Promise(function(p) { p() });
console.log("waiting");
if (!promiseBug) setTimeout(cycle);
};
cycle();
var frame = chrome.app.window.current();
var setTheme = function() {

View file

@ -16,7 +16,7 @@ define([
};
File.prototype = {
open: function(mode) {
open: function(mode, c) {
var self = this;
mode = mode || "open";
//mode is "open" or "save"
@ -24,45 +24,40 @@ define([
"open": "openWritableFile",
"save": "saveFile"
};
var deferred = M.deferred();
chrome.fileSystem.chooseEntry({
type: modes[mode]
}, function(entry) {
//cancelling acts like an error, but isn't.
if (!entry) return deferred.fail(chrome.runtime.lastError);
if (!entry) return c(chrome.runtime.lastError);
self.entry = entry;
deferred.done(self)
c(null, self);
});
return deferred.promise();
},
read: function() {
read: function(c) {
var self = this;
var deferred = M.deferred();
if (!self.entry) {
console.error(self);
deferred.fail("File not opened");
c("File not opened");
}
var reader = new FileReader();
reader.onload = function() {
deferred.done(reader.result);
c(null, reader.result);
};
reader.onerror = function(err) {
console.error("File read error!");
deferred.fail(err);
c(err);
};
self.entry.file(function(f) {
reader.readAsText(f);
});
return deferred.promise();
},
write: function(data) {
write: function(data, c) {
var self = this;
c = c || function() {};
if (!self.entry) {
//guard against cases where we accidentally write before opening
return self.open("save").then(function() {
@ -70,8 +65,6 @@ define([
});
}
var deferred = M.deferred();
M.chain(
//check permissions
function(next) {
@ -85,7 +78,7 @@ define([
self.entry = entry;
next();
} else {
deferred.fail("Couldn't open file as writable");
c("Couldn't open file as writable");
}
});
}
@ -96,12 +89,12 @@ define([
self.entry.createWriter(function(writer) {
writer.onerror = function(err) {
console.error(err);
deferred.fail(err);
c(err);
}
writer.onwriteend = function() {
//after truncation, actually write the file
writer.onwriteend = function() {
deferred.done();
c();
self.onWrite();
}
var blob = new Blob([data]);
@ -111,53 +104,44 @@ define([
});
}
);
return deferred.promise();
},
stat: function() {
stat: function(c) {
var self = this;
var promise = new Promise(function(ok, fail) {
if (self.entry) {
return self.entry.file(function(f) {
ok(f);
});
}
fail("No file entry");
});
return promise;
if (self.entry) {
return self.entry.file(function(f) {
c(null, f);
});
}
c("No file entry");
},
retain: function() {
return chrome.fileSystem.retainEntry(this.entry);
},
restore: function(id) {
restore: function(id, c) {
var self = this;
var deferred = M.deferred();
chrome.fileSystem.isRestorable(id, function(is) {
if (is) {
chrome.fileSystem.restoreEntry(id, function(entry) {
if (!entry) return deferred.fail("restoreEntry() failed for " + id);
if (!entry) return c("restoreEntry() failed for " + id);
self.entry = entry;
deferred.done();
c();
});
} else {
deferred.fail("isRestorable() returned false for " + id);
c("isRestorable() returned false for " + id);
}
});
return deferred.promise();
},
getPath: function() {
getPath: function(c) {
var self = this;
var promise = new Promise(function(ok, fail) {
if (!self.entry) return fail("No backing entry, cannot get path")
chrome.fileSystem.getDisplayPath(self.entry, ok);
if (!self.entry) return fail("No backing entry, cannot get path");
chrome.fileSystem.getDisplayPath(self.entry, function(path) {
c(null, path);
});
return promise;
}
};

View file

@ -30,27 +30,25 @@ define([
};
SyncFile.prototype = {
name: "",
open: function(name) {
open: function(name, c) {
this.name = name;
this.entry.name = name;
var self = this;
var promise = new Promise(function(ok, fail) {
resolve(self);
});
return promise;
if (c) c(null, this);
},
read: function() {
read: function(c) {
var name = this.name;
return sync.get(this.name);
sync.get(this.name).then(function(data) {
c(null, data);
});
},
write: function(content) {
var self = this;
write: function(content, c) {
return sync.set(this.name, content).then(function() {
command.fire("settings:change-local");
c();
});
},
retain: function() { return false; },
restore: function() { return new Promise.reject() }
restore: function(c) { c("Cannot restore sync storage files") }
};
return SyncFile;

View file

@ -52,10 +52,10 @@ define([
this.fileName = file.entry.name;
this.modifiedAt = new Date();
var self = this;
if (!this.file.virtual) file.getPath().then(function(path) {
if (!this.file.virtual) file.getPath(function(err, path) {
self.path = path;
command.fire("session:render");
})
});
}
Tab.prototype.save = function(as) {
@ -70,27 +70,30 @@ define([
var deferred = M.deferred();
var whenOpen = function() {
self.file.write(content).then(function() {
self.file.write(content, function(err) {
if (err) {
return deferred.fail(err);
}
self.modifiedAt = new Date();
self.modified = false;
command.fire("session:render");
deferred.done();
}, deferred.fail.bind(deferred));
});
};
if (!self.file || as) {
var file = new File();
file.open("save")
.then(function() {
self.file = file;
self.fileName = file.entry.name;
delete self.syntaxMode;
self.detectSyntax();
}, function(err) {
file.open("save", function(err) {
if (err) {
dialog(err);
deferred.fail();
})
.then(whenOpen);
return deferred.fail(err);
}
self.file = file;
self.fileName = file.entry.name;
delete self.syntaxMode;
self.detectSyntax();
whenOpen();
});
} else {
whenOpen();
}

View file

@ -138,15 +138,16 @@ define([
self.render();
var file = new File();
file.onWrite = self.watchProjectFile.bind(self);
file.restore(data.retainedProject).then(function(f) {
file.read().then(function(data) {
file.restore(data.retainedProject, function(err, f) {
file.read(function(err, data) {
if (err) {
self.loading = false;
self.render();
return chrome.storage.local.remove("retainedProject");
}
self.projectFile = file;
self.loadProject(JSON.parse(data));
});
}, function(err) {
self.loading = false;
self.render();
return chrome.storage.local.remove("retainedProject");
});
}
});
@ -336,7 +337,7 @@ define([
if (!tab.file || tab.file.virtual) {
return c(false);
}
tab.file.getPath().then(function(p) {
tab.file.getPath(function(err, p) {
if (p == path) {
sessions.setCurrent(tab);
found = true;
@ -349,7 +350,7 @@ define([
function() {
if (found) return;
var file = new File(node.entry);
file.read().then(function(data) {
file.read(function(err, data) {
sessions.addFile(data, file);
});
}
@ -375,7 +376,7 @@ define([
var file = new File();
var watch = this.watchProjectFile.bind(this);
var self = this;
file.open("save").then(function() {
file.open("save", function() {
file.write(json);
var id = file.retain();
chrome.storage.local.set({retainedProject: id});
@ -389,21 +390,20 @@ define([
openProjectFile: function() {
var file = new File();
var self = this;
file
.open()
.then(file.read.bind(file))
.then(function(data) {
file.open(function() {
file.read(function(err, data) {
self.loadProject(data);
var id = file.retain();
chrome.storage.local.set({retainedProject: id});
self.projectFile = file;
file.onWrite = self.watchProjectFile.bind(self);
});
file.onWrite = self.watchProjectFile;
});
},
watchProjectFile: function() {
var self = this;
this.projectFile.read().then(function(data) {
this.projectFile.read(function(err, data) {
self.loadProject(data);
});
},
@ -445,7 +445,7 @@ define([
return dialog("No project opened.");
}
var self = this;
this.projectFile.read().then(function(data) {
this.projectFile.read(function(err, data) {
sessions.addFile(data, self.projectFile);
});
},

View file

@ -1,7 +1,7 @@
{
"name": "Caret",
"description": "Professional text editing for Chrome and Chrome OS",
"version": "1.4.6",
"version": "1.4.7",
"manifest_version": 2,
"icons": {
"128": "icon-128.png"