-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
async
function support
#1390
async
function support
#1390
Conversation
Also, I ran the benchmarks -- there is no difference in performance, whether the environment supports async functions or not. |
.travis.yml
Outdated
# - node_js: "6" | ||
# addons: | ||
# firefox: "49.0" | ||
# env: BROWSER=true MAKE_TEST=true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are we disabling this stuff? Can we just up the firefox version?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disabled this thinking it was an issue with karma, but it's a syntax error. I'll investigate further and re-enable. We could test both 45 (ESR, no async
support) and 52 (async
supported).
lib/autoInject.js
Outdated
|
||
if (isArray(taskFn)) { | ||
params = taskFn.slice(0, -1); | ||
taskFn = taskFn[taskFn.length - 1]; | ||
|
||
newTasks[key] = params.concat(params.length > 0 ? newTask : taskFn); | ||
} else if (taskFn.length === 1) { | ||
} else if ((!fnIsAsync && taskFn.length === 1) || | ||
(fnIsAsync && taskFn.length === 0)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fnIsAsync + taskFn.length === 1
=P (dont do it lol)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤢
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I should probably factor this condition out into a hasNoDeps
variable.
lib/doWhilst.js
Outdated
@@ -19,7 +20,7 @@ import onlyOnce from './internal/onlyOnce'; | |||
* passes. The function is passed a `callback(err)`, which must be called once | |||
* it has completed with an optional `err` argument. Invoked with (callback). | |||
* @param {Function} test - synchronous truth test to perform after each |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a AsyncFunction
jsdoc tag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about the best way to document this. For sure, add something to the intro.md
, but we have lots of repeated docs where we describe the iteratee function as a node-style async function. It would be nice to centralize the description of what Async accepts, with each Async method just describing the non-callback parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps an external
definition if jsdoc doesn't support some way of documenting an async function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also thinking of using a @typedef
, like we do for the return values of queue
/cargo
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really don't like how the @typedef
s look in our code. I'd rather just link to MDN
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check the latest commit. It's cleaner than the JSDoc docs make it out to be...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 for using typedef
for this. Does this mean most of the docs should to be updated to reflect that iteratee
should be an AsyncFunction
type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, lots of docs to update. 😓 It does create a nice link to the central AsyncFunction
docs in the rendered docs, though.
lib/internal/applyEach.js
Outdated
|
||
export default function applyEach(eachfn) { | ||
return rest(function(fns, args) { | ||
var go = initialParams(function(args, callback) { | ||
var that = this; | ||
return eachfn(fns, function (fn, cb) { | ||
return eachfn(arrayMap(fns, wrapAsync), function (fn, cb) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fns
can be a array|object|iterable
lib/internal/applyEach.js
Outdated
|
||
export default function applyEach(eachfn) { | ||
return rest(function(fns, args) { | ||
var go = initialParams(function(args, callback) { | ||
var that = this; | ||
return eachfn(fns, function (fn, cb) { | ||
return eachfn(arrayMap(fns, wrapAsync), function (fn, cb) { | ||
fn.apply(that, args.concat(cb)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do wrapAsync
here instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. 👍
var supported; | ||
try { | ||
/* eslint no-eval: 0 */ | ||
supported = isAsync(eval('(async function () {})')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eval is evil. Why not Function?
supported = isAsync(new Function("return (async function () {})")());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eval
can be abused in the same way that new Function
can be abused. I'd rather just use eval
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new Function()
and eval
are equivalently evil. Here, they are necessary, because there is no other way to detect async
support without causing a parse error that halts JS execution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm good with using eval
here instead of new Function
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really excited for this, awesome work! 😄
lib/asyncify.js
Outdated
@@ -48,7 +48,7 @@ import initialParams from './internal/initialParams'; | |||
* } | |||
* ], callback); | |||
* | |||
* // es6 example | |||
* // es2017 example |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be useful to add a note here that async
functions are supported out of the box (when not transpiled)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we should clarify here.
lib/doWhilst.js
Outdated
@@ -19,7 +20,7 @@ import onlyOnce from './internal/onlyOnce'; | |||
* passes. The function is passed a `callback(err)`, which must be called once | |||
* it has completed with an optional `err` argument. Invoked with (callback). | |||
* @param {Function} test - synchronous truth test to perform after each |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 for using typedef
for this. Does this mean most of the docs should to be updated to reflect that iteratee
should be an AsyncFunction
type?
var supported; | ||
try { | ||
/* eslint no-eval: 0 */ | ||
supported = isAsync(eval('(async function () {})')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm good with using eval
here instead of new Function
.
lib/index.js
Outdated
* This type of function is also referred to as a "Node-style async function". | ||
* | ||
* Wherever we accept a Node-style async function, we also directly accept an | ||
* ES2017 `async` function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/index.js
Outdated
* ES2017 `async` function. | ||
* In this case, the `async` function will not be passed a callback, and any | ||
* thrown error will be used as the `err` argument of a theoretical callback, | ||
* and the return value will be used as the `result` value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean the
async function will not be passed a callback
? Do you mean the result of the async function?
lib/index.js
Outdated
* thrown error will be used as the `err` argument of a theoretical callback, | ||
* and the return value will be used as the `result` value. | ||
* | ||
* Note that we can only detect native `async function`s in this case. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note, due to JavaScript limitations, we can only detect native
async function
s and not polyfilled implementations.
@megawac @hargasinski Many doc updates for your 👀. 😓 |
@@ -6,7 +6,7 @@ | |||
"es6": true | |||
}, | |||
"parserOptions": { | |||
"ecmaVersion": 6, | |||
"ecmaVersion": 8, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is es8? can we set this to 2017/2018 whatever?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ES8 is eslint's shorthand for ES2017. No, you can't use "2017"... Just subtract 2009. 😛
"babel-plugin-add-module-exports": "^0.2.1", | ||
"babel-plugin-istanbul": "^2.0.1", | ||
"babel-plugin-transform-es2015-modules-commonjs": "^6.3.16", | ||
"babel-preset-es2015": "^6.3.13", | ||
"babel-preset-es2017": "^6.22.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we using this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, otherwise babel can't parse the test file where we use async
functions, even if they're being used natively.
👏 awesome work, pretty excited for this |
I'm a little late, but really great work. I'm excited about this 💯 |
#1386
This adds support for passing
async
functions wherever it might make sense.Obviously we are duplicating some core functionality with things like
map
andrace
, but this allows us to treat things uniformly. We do have some good value to add with functions that limit concurrency, and adding more higher-order operations that justmap
andeach
(as you would get withPromise.map()
andPromise.all()
). "Lodash forasync
functions" is a good thing to strive to be.Most of the control flow functions are of dubious value, (
waterfall
,parallel
,whilst
), but you can do some really neat things withauto
andqueue
. (I really love theautoInject
shorthand test!)The utility functions are a bit strange.
retry
,reflect
,memoize
andtimeout
now take in anasync
function and return a callback-accepting function. It feels like those should create a Promise-returning function.