Skip to content

Instantly share code, notes, and snippets.

@marcoscaceres
Last active August 29, 2015 14:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcoscaceres/29275058c3684b354e3c to your computer and use it in GitHub Desktop.
Save marcoscaceres/29275058c3684b354e3c to your computer and use it in GitHub Desktop.
async.js
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* This is an approximate implementation of ES7's async-await pattern.
* see: https://github.com/tc39/ecmascript-asyncawait
*
* It allows for simple creation of async function and "tasks".
*
* For example:
*
* var myThinger = {
* doAsynThing: async(function*(url){
* var result = yield fetch(url);
* return process(result);
* });
* }
*
* And Task-like things can be created as follows:
*
* var myTask = async(function*{
* var result = yield fetch(url);
* return result;
* });
* //returns a promise
*
* myTask().then(doSomethingElse);
*
*/
(function(exports) {
"use strict";
function async(func, self) {
return function asyncFunction() {
const functionArgs = Array.from(arguments);
return new Promise(function(resolve, reject) {
var gen;
if (typeof func !== "function") {
reject(new TypeError("Expected a Function."));
}
//not a generator, wrap it.
if (func.constructor.name !== "GeneratorFunction") {
gen = (function*() {
return func.apply(self, functionArgs);
}());
} else {
gen = func.apply(self, functionArgs);
}
try {
step(gen.next(undefined));
} catch (err) {
reject(err);
}
function step({value, done}) {
if (done) {
return resolve(value);
}
if (value instanceof Promise) {
return value.then(
result => step(gen.next(result)),
error => {
try {
step(gen.throw(error));
} catch (err) {
throw err;
}
}
).catch(err => reject(err));
}
step(gen.next(value));
}
});
};
}
exports.async = async;
}(this || self));
// Tests
let expected = function(result) {
console.assert(result instanceof Error, 'Expected exception.');
};
[undefined, null, 1, [], {}, 'string']
.forEach(invalidType => {
async(invalidType)().then(
(s) => expected, (err) => expected
);
});
let expectedPass = function(result) {
let msg = `Expect pass. Got ${result}`;
console.assert(result === 'pass', msg);
};
async(function* () {
let x = yield Promise.resolve('testing');
console.assert(x === 'testing', 'Expected testing');
return 'pass';
})().then(expectedPass, expectedPass);
async(function* () {
let x = yield Promise.resolve('testing');
let y = yield Promise.resolve(x + '123');
let z = yield y + '456';
console.assert(z === 'testing123456', `Expected testing123456. Got: ${z}`);
return 'pass';
})().then(expectedPass, expectedPass);
async(function* () {
let x = yield Promise.resolve('testing');
let y = yield Promise.resolve(x + '123');
let z = yield Promise.resolve(y + '456');
console.assert(z === 'testing123456', `Expected testing123456. Got: ${z}`);
return 'pass';
})().then(expectedPass, expectedPass);
//Testing try/catch
async(function* () {
let err;
try {
let x = yield Promise.reject(new Error('testing111'));
} catch (err) {
console.assert(err.message === 'testing111', 'Expected testing111');
}
return 'pass';
})().then(expectedPass, expectedPass);
async(function* () {
let err;
try {
let x = yield Promise.reject(new Error('testing111'));
} catch (err) {
console.assert(err.message === 'testing111', 'Expected testing111');
}
let w = yield('recovered');
console.assert(w === 'recovered', 'Expected string recovered');
return 'pass';
})().then(expectedPass, expectedPass);
async(function* () {
try {
let x = yield Promise.reject(new Error('testing111'));
} catch (err) {
console.assert(err.message === 'testing111', 'Expected testing111')
}
let w = yield('recovered');
let z = yield w + '123';
console.assert(z === 'recovered123', 'Expected string recovered123');
return 'pass';
})().then(expectedPass, expectedPass);
async(function* () {
try {
let x = yield Promise.reject(new Error('testing111'));
} catch (err) {
console.assert(
err.message === 'testing111', 'Expected testing111'
);
}
let w = yield('recovered');
let z = yield w + '123';
console.assert(z === 'recovered123', 'Expected string recovered123');
return 'pass';
})().then(expectedPass, expectedPass);
async(function* () {
try {
let x = yield Promise.reject(new Error('testing111'));
} catch (err) {
console.assert(
err.message === 'testing111', 'Expected testing111'
);
}
let w = yield('recovered');
let z = yield w + '123';
let xxx = yield Promise.resolve(z);
console.assert(xxx === 'recovered123', 'Expected string recovered123');
return 'pass';
})().then(expectedPass, expectedPass);
async(function* () {
for (let i = 0; i < 10; i++) {
let r = yield fetch('/?test=' + i);
let text = r.text();
}
return 'pass';
})().then((r) => {
console.assert(r === 'pass', 'Expected pass')
}, err => console.assert(false, 'did not expect fail'));
async(function* (arg1) {
console.assert(arg1 === undefined, 'Argument 1 is undefined.')
return 'pass';
})().then(expectedPass, expectedPass);
async(function* (arg1) {
console.assert(arg1 === 'pass', 'Argument 1 is pass.')
return 'pass';
})('pass').then(expectedPass, expectedPass);
async(function* (arg1, arg2, arg3) {
console.assert(arg1 === 1, 'Argument 1 is 1.');
console.assert(arg2 === 2, 'Argument 2 is 2.');
console.assert(arg3 === 3, 'Argument 3 is 3.');
console.assert(arguments.length === 3, 'Arguments length is 3.');
return 'pass';
})(1, 2, 3).then(expectedPass, expectedPass);
//non-async async
async(function(){
return 'pass'
})().then(expectedPass, expectedPass);
async(function (arg1, arg2, arg3) {
console.assert(arg1 === 1, 'Argument 1 is 1.');
console.assert(arg2 === 2, 'Argument 2 is 2.');
console.assert(arg3 === 3, 'Argument 3 is 3.');
console.assert(arguments.length === 3, 'Arguments length is 3.');
return 'pass';
})(1, 2, 3).then(expectedPass, expectedPass);
//bind tests
var obj = {value: '123', value2: 321}
async(function* (arg1) {
console.assert(this.value === '123', 'Bound `this.value` 123.');
console.assert(this.value2 === 321, 'Bound `this.value2` 321.');
return 'pass';
},obj)().then(expectedPass, expectedPass);
async(function* (arg1, arg2, arg3) {
console.assert(this.value === '123', 'Bound `this.value` 123.');
console.assert(this.value2 === 321, 'Bound `this.value2` 321.');
console.assert(arg1 === 1, 'Argument 1 is 1.');
console.assert(arg2 === 2, 'Argument 2 is 2.');
console.assert(arg3 === 3, 'Argument 3 is 3.');
console.assert(arguments.length === 3, 'Arguments length is 3.');
return 'pass';
}, obj)(1, 2, 3).then(expectedPass, expectedPass);
async(function (arg1) {
console.assert(this.value === '123', 'Bound `this.value` 123.');
console.assert(this.value2 === 321, 'Bound `this.value2` 321.');
return 'pass';
},obj)().then(expectedPass, expectedPass);
async(function (arg1, arg2, arg3) {
console.assert(this.value === '123', 'Bound `this.value` 123.');
console.assert(this.value2 === 321, 'Bound `this.value2` 321.');
console.assert(arg1 === 1, 'Argument 1 is 1.');
console.assert(arg2 === 2, 'Argument 2 is 2.');
console.assert(arg3 === 3, 'Argument 3 is 3.');
console.assert(arguments.length === 3, 'Arguments length is 3.');
return 'pass';
}, obj)(1, 2, 3).then(expectedPass, expectedPass);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment