Skip to content

Allow Promises from lifecycle functions #3000

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 50 additions & 37 deletions src/core/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,12 +268,10 @@ var p5 = function(sketch, node, sync) {
obj[method] = this._wrapPreload(obj, method);
}

userPreload();
this._runIfPreloadsAreDone();
this._incrementPreload();
Promise.resolve(userPreload()).then(this._decrementPreload.bind(this));
} else {
this._setup();
this._runFrames();
this._draw();
this._runIfPreloadsAreDone();
}
}.bind(this);

Expand All @@ -284,9 +282,10 @@ var p5 = function(sketch, node, sync) {
if (loadingScreen) {
loadingScreen.parentNode.removeChild(loadingScreen);
}
context._setup();
context._runFrames();
context._draw();
return Promise.resolve()
.then(context._setup.bind(context))
.then(context._runFrames.bind(context))
.then(context._draw.bind(context));
}
};

Expand Down Expand Up @@ -333,22 +332,28 @@ var p5 = function(sketch, node, sync) {
}
}

// Short-circuit on this, in case someone used the library in "global"
// mode earlier
if (typeof context.setup === 'function') {
context.setup();
}
var self = this;

// unhide any hidden canvases that were created
var canvases = document.getElementsByTagName('canvas');
for (var i = 0; i < canvases.length; i++) {
var k = canvases[i];
if (k.dataset.hidden === 'true') {
k.style.visibility = '';
delete k.dataset.hidden;
}
}
this._setupDone = true;
return Promise.resolve()
.then(function() {
// Short-circuit on this, in case someone used the library in "global"
// mode earlier
if (typeof context.setup === 'function') {
return context.setup();
}
})
.then(function() {
// unhide any hidden canvases that were created
var canvases = document.getElementsByTagName('canvas');
for (var i = 0; i < canvases.length; i++) {
var k = canvases[i];
if (k.dataset.hidden === 'true') {
k.style.visibility = '';
delete k.dataset.hidden;
}
}
self._setupDone = true;
});
}.bind(this);

this._draw = function() {
Expand All @@ -364,31 +369,39 @@ var p5 = function(sketch, node, sync) {
// in sync with the browser. note that we have to draw once even
// if looping is off, so we bypass the time delay if that
// is the case.
var self = this;
var promise = Promise.resolve();
var epsilon = 5;
if (
!this._loop ||
time_since_last >= target_time_between_frames - epsilon
) {
//mandatory update values(matrixs and stack)

this.redraw();
this._frameRate = 1000.0 / (now - this._lastFrameTime);
this._lastFrameTime = now;

// If the user is actually using mouse module, then update
// coordinates, otherwise skip. We can test this by simply
// checking if any of the mouse functions are available or not.
// NOTE : This reflects only in complete build or modular build.
if (typeof this._updateMouseCoords !== 'undefined') {
this._updateMouseCoords();
}
promise = promise.then(function() {
return self.redraw();
});
promise = promise.then(function() {
self._frameRate = 1000.0 / (now - self._lastFrameTime);
self._lastFrameTime = now;

// If the user is actually using mouse module, then update
// coordinates, otherwise skip. We can test this by simply
// checking if any of the mouse functions are available or not.
// NOTE : This reflects only in complete build or modular build.
if (typeof self._updateMouseCoords !== 'undefined') {
self._updateMouseCoords();
}
});
}

// get notified the next time the browser gives us
// an opportunity to draw.
if (this._loop) {
this._requestAnimId = window.requestAnimationFrame(this._draw);
}
promise.then(function() {
if (self._loop) {
self._requestAnimId = window.requestAnimationFrame(self._draw);
}
});
}.bind(this);

this._runFrames = function() {
Expand Down
24 changes: 16 additions & 8 deletions src/core/structure.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ p5.prototype.pop = function() {
*
* @method redraw
* @param {Integer} [n] Redraw for n-times. The default value is 1.
* @return {Promise} A promise that resolves once all redraws are finished.
* @example
* <div><code>
* var x = 0;
Expand Down Expand Up @@ -308,6 +309,7 @@ p5.prototype.pop = function() {
*
*/
p5.prototype.redraw = function(n) {
var promise = Promise.resolve();
var numberOfRedraws = parseInt(n);
if (isNaN(numberOfRedraws) || numberOfRedraws < 1) {
numberOfRedraws = 1;
Expand All @@ -324,16 +326,22 @@ p5.prototype.redraw = function(n) {
f.call(self);
};
for (var idxRedraw = 0; idxRedraw < numberOfRedraws; idxRedraw++) {
this.resetMatrix();
if (this._renderer.isP3D) {
this._renderer._update();
}
this._setProperty('frameCount', this.frameCount + 1);
this._registeredMethods.pre.forEach(callMethod);
userDraw();
this._registeredMethods.post.forEach(callMethod);
promise = promise
.then(function() {
self.resetMatrix();
if (self._renderer.isP3D) {
self._renderer._update();
}
self._setProperty('frameCount', self.frameCount + 1);
self._registeredMethods.pre.forEach(callMethod);
})
.then(userDraw)
.then(function() {
self._registeredMethods.post.forEach(callMethod);
});
}
}
return promise;
};

module.exports = p5;
23 changes: 23 additions & 0 deletions test/js/p5_helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
function promisedSketch(sketch_fn) {
var myInstance;
var promise = new Promise(function(resolve, reject) {
myInstance = new p5(function(sketch) {
return sketch_fn(sketch, resolve, reject);
});
});

promise.catch(function() {}).then(function() {
myInstance.remove();
});
return promise;
};

function testSketchWithPromise(name, sketch_fn) {
var test_fn = function() {
return promisedSketch(sketch_fn);
};
test_fn.toString = function() {
return sketch_fn.toString();
};
return test(name, test_fn);
};
1 change: 1 addition & 0 deletions test/test-minified.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<script src="js/sinon.js" type="text/javascript" ></script>
<script src="js/modernizr.js" type="text/javascript" ></script>
<script src="js/chai_helpers.js" type="text/javascript" ></script>
<script src="js/p5_helpers.js" type="text/javascript" ></script>

<!-- Include anything you want to test -->
<script src="../lib/p5.min.js" type="text/javascript" ></script>
Expand Down
1 change: 1 addition & 0 deletions test/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<script src="js/sinon.js" type="text/javascript" ></script>
<script src="js/modernizr.js" type="text/javascript" ></script>
<script src="js/chai_helpers.js" type="text/javascript" ></script>
<script src="js/p5_helpers.js" type="text/javascript" ></script>

<!-- Include anything you want to test -->
<script src="../lib/p5.js" type="text/javascript" ></script>
Expand Down
114 changes: 87 additions & 27 deletions test/unit/core/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,59 +18,119 @@ suite('Core', function() {
// readyState is "loading" and we can verify that the code is doing the
// right thing during page load.

var myp5 = new p5(function() {}, null, true);
var isDrawingContextDefined = myp5.drawingContext !== undefined;
var isPreloadCalled = false;
var myp5 = new p5(
function(s) {
s.preload = function() {
isPreloadCalled = true;
};
},
null,
true
);
var preloadedHere = isPreloadCalled;
teardown(function() {
myp5.remove();
});

test('should define drawContext synchronously', function() {
assert.ok(isDrawingContextDefined);
test('should start preload immediately', function() {
assert.ok(preloadedHere);
});
});

suite('new p5(sketch, null, false)', function() {
var myp5 = new p5(function() {}, null, false);
var isDrawingContextDefined = myp5.drawingContext !== undefined;
var isPreloadCalled = false;
var myp5 = new p5(
function(s) {
s.preload = function() {
isPreloadCalled = true;
};
},
null,
false
);
var preloadedHere = isPreloadCalled;
teardown(function() {
myp5.remove();
});

test('should define drawContext asynchronously', function() {
assert.equal(isDrawingContextDefined, false);
assert.isDefined(myp5.drawingContext);
test('should start preload asynchronously', function() {
assert.isFalse(preloadedHere);
assert.isTrue(isPreloadCalled);
});
});

suite('new p5(sketch, node, true)', function() {
var myp5 = new p5(function() {}, node, true);
var isDrawingContextDefined = myp5.drawingContext !== undefined;
var isPreloadCalled = false;
var myp5 = new p5(
function(s) {
s.preload = function() {
isPreloadCalled = true;
};
},
node,
true
);
var preloadedHere = isPreloadCalled;
teardown(function() {
myp5.remove();
});

test('should define drawContext synchronously', function() {
assert.ok(isDrawingContextDefined);
test('should start preload synchronously', function() {
assert.isTrue(preloadedHere);
});
});

suite('new p5(sketch, node)', function() {
var myp5 = new p5(function() {}, node);
var isDrawingContextDefined = myp5.drawingContext !== undefined;
var isPreloadCalled = false;
var myp5 = new p5(function(s) {
s.preload = function() {
isPreloadCalled = true;
};
}, node);
var preloadedHere = isPreloadCalled;
teardown(function() {
myp5.remove();
});

test('should define drawContext asynchronously', function() {
assert.equal(isDrawingContextDefined, false);
assert.isDefined(myp5.drawingContext);
test('should start preload asynchronously', function() {
assert.isFalse(preloadedHere);
assert.isTrue(isPreloadCalled);
});
});

suite('new p5(sketch, true)', function() {
var myp5 = new p5(function() {}, true);
var isDrawingContextDefined = myp5.drawingContext !== undefined;
var isPreloadCalled = false;
var myp5 = new p5(function(s) {
s.preload = function() {
isPreloadCalled = true;
};
}, true);
var preloadedHere = isPreloadCalled;
teardown(function() {
myp5.remove();
});

test('should define drawContext synchronously', function() {
assert.ok(isDrawingContextDefined);
test('should start preload synchronously', function() {
assert.isTrue(preloadedHere);
});
});

suite('new p5(sketch)', function() {
var myp5 = new p5(function() {});
var isDrawingContextDefined = myp5.drawingContext !== undefined;
var isPreloadCalled = false;
var myp5 = new p5(function(s) {
s.preload = function() {
isPreloadCalled = true;
};
});
var preloadedHere = isPreloadCalled;
teardown(function() {
myp5.remove();
});

test('should define drawContext asynchronously', function() {
assert.equal(isDrawingContextDefined, false);
assert.isDefined(myp5.drawingContext);
test('should start preload asynchronously', function() {
assert.isFalse(preloadedHere);
assert.isTrue(isPreloadCalled);
});
});

Expand Down
Loading