This article is the fourth in the series of "A JSer's Dart Learning Log". This series of articles mainly aims to explore the similarities and differences between JS and Dart, while reviewing and consolidating JS while smoothly transitioning to the Dart language.
Since the author is still a beginner to Dart, his understanding may be superficial and one-sided. If you know the worms, I hope you can correct me.
Unless otherwise specified, the JS in this article contains all the features from ES5 to ES2021, and the Dart version is 2.0 or higher.Google originally developed Dart as the successor of JS, so it has borrowed many features of JS in its design, such as event-driven and single-threaded, which makes their asynchronous programming approach very similar.
1. Use callback function
Common ground
Both JS and Dart are adhering to the concept of "everything is an object". There is nothing more than a function. Passing a function as a parameter in order to call it at the right time is the simplest asynchronous programming solution. This function is the callback function .
> /* ******************** Both JS and Dart ******************** */ > var func = (param) => param + 1; > var caller = (callback) => callback(1);
the difference
- Dart's asynchronous process is different from JS-it is blocking, and callback functions alone cannot solve the problem. Therefore callback function style is the characteristic of JS (for the two languages) .
Dart specific
1. Types of callback functions
When defining a function, the callback function is one of its parameters, and the parameters of the function can be declared in type. There is no exception to the callback function. However, due to the many elements of the function, it is different from other types of declarations——
Other types: type keyword in front of the variable name :void func(int a, Map<String, dynamic> b){ // Do something }
。
Function type: The type of the function isFunction
, but the syntax for declaring the parameter type as a function is notFunction callback
:// callback 第一个参数为 `num` 类型,第二个参数为 `int`类型 // callback 的返回值为 `String` 类型 // 如果这些类型都未显式声明的话,则全部都是 dynamic void func(String callback(num a, int b)){ // Do something }
2. Use the generator function
ES6 has added generator functions, which can temporarily interrupt execution and continue execution after "waking up". This feature complements asynchronous processes, so generator functions are also used to handle asynchronous processes.
Dart also has generator functions, which are similar in concept to JS generators, but there are many differences in syntax and usage.
Common ground
1. Use *
and yeild
Use
*
declare a generator function, use theyield
keyword to pause the function and generate the value.> /* JS */ | /* Dart */ > function* gen(max) { | gen(int max) sync* { > var state = 0; | var state = 0; > while(state < max) { | while(state < max) { > yield state ++; | yeild state ++; > } | } > } | } > const reader = gen(6); | final reader = gen(6); > console.log(reader.next().value); | print('${render.elementAt(0)}'); > // 0 | // 0
The generator function is suitable for some scenarios where the call is repeatedly triggered, such as the interface event of
WebSocket
2. "Lazy" evaluation
- The generator function execution
yield
, and returns a specific object. Calling a specific method of this object, the function will continue to run until it encounters the nextyield
.
the difference
1. Dart generators are divided into synchronous and asynchronous
- JS has only one kind of generator, and the returned iterable objects are all
Generator
; - Dart generators are divided into synchronous (
sync
) and asynchronous (async
). The synchronous generator function returns theIterator
instance, and the asynchronous generator returns theStream
instance.
3. Future
VS Promise
Common ground
1. Wrap the return value of the async
Although the history of asynchronous programming is quite long, asynchronous functions are a young concept, so the first question of introducing asynchronous functions into programming languages is: How to embed asynchronous functions into synchronous logic flow?
For this question, the answer given by JS is Promise
, correspondingly, Dart's answer is Future
:
> /* JS */ | // Dart
> async function asyncFunc() { | asyncFunc() async {
> return await 'yes'; | return await 'yes';
> } | }
> console.log(asyncFunc()); | print(asyncFunc());
> // Promise {<pending>} | // Instance of '_Future<dynamic>'
2. .then
method and chain call
Both schemes use .then
syntax to subscribe to the final result of the asynchronous process:
> /* JS */ | // Dart
> asyncFunc().then( | asyncFunc().then(
> (res) => | (res) =>
> console.log(`Got ${res}`) | print('Got $res')
> ) | )
> // Got yes | // Got yes
。
In addition, the .then
method will also return a new Promise/Future
, subscribe to this return value to get the return value of the callback function (or the value Promise/Future
> /* JS */ | // Dart
> async function plus1(v = 0) { | int plus1(int v) async {
> return await v + 1; | return await v + 1;
> } | }
> function plus2(v = 0) { | int plus2(int v) {
> return v + 2; | return v + 2;
> } | }
> plus1().then(plus1) | plus1().then(plus1)
> .then(plus2).then(console.log); | .then(plus2).then(print);
> // 4 | // 4
the difference
1. Dart type annotation
In this series of articles, this feature of Dart is a cliché. The generic syntax used inDart
Future
and the type of the value it wraps:
Future<int> foo async {
return 1;
}
2. Promise.all
vs Future.wait
For a while, I don’t know if it should be regarded as common or different, because the grammar is exactly the same, only the keywords are different:
> /* JS */ | // Dart
> Promise.all([ | Future.wait([
> plus1(), | plus1(),
> plus1() | plus1()
> ]).then( | ]).then(
> () => console.log('All done'); | () => print('All done');
> ); | );
3. The parameters of the constructor are different
The function parameters passed in are in different forms
Both need to pass in a function, but the form of this function is different.
Promise
ofexcutor
has two positional parameters:resolve
andreject
.Promise
the "packaging" value, thatresolve
return value of the function;Future
ofcomputation
function is no argument,Future
packaged preciselycomputation
return value.> /* JS */ | // Dart > const a = new Promise( | final a = /*new*/ Future( > (resolve, reject) => resolve(1) | () => 1 > ); | ); > console.log(await a); | print(await a); > // 1 | // 1
computation
default asynchronous execution
Promise
ofexcutor
used to initializePromise
, and the asynchronous process of JS will not be blocked, so it is executed synchronously;Future
ofcomputation
directly used to obtain the value, which is executed asynchronously:> /* JS */ | // Dart > var mut = 0; | var mut = 0; > const a = new Promise( | final a = /*new*/ Future( > function (resolve, reject) { | () { > mut++; | mut++; > resolve(1); | return 1; > } | } > ); | ); > console.log(mut); | print(mut); > // 1 | // 0
;
If you want to execute
computation
synchronously, you should use the named constructorFuture.sync
:int mut = 0; final a = Future.sync((){ mut++; return mut; }); print(mut); // 1
4. Packing values and errors
- JS uses
Promise.resolve(value)
tovalue
in aPromise
, and usesPromise.reject(error)
package errorerror
; - Dart's
Future.value(value)
andFuture.error(error)
realize the above functions respectively.
Actually I don't know what is the use of these two kinds of packaging.
5. Future
undertakes more tasks of asynchronous programming
Future.delayed
VS window.setTimeout
setTimeout
interface provided by the top-level object to register the delayed task, which is a callback style interface;Dart uses the named constructor
Future.delayed
register delayed tasks:> /* JS */ | // Dart > var task = setTimeout( | var task = Future.delayed( > () => { | Duration(milliseconds: 100), > console.log('done'); | () { > }, | print('done'); > 100 | } > }; | };
Dart uses the
Duration
class to construct the time difference, which is much more intuitive than the JS default milliseconds (but it's a bit cumbersome to write, I don't know if there is syntactic sugar).
Future.microstack
VS Promise.resolve().then
- The most convenient solution for
Promise.resolve().then
JS is 061628f7d610b9, (of course, the premise is to use thePromise
provided at runtime or the reliablepolyfill
solution). Although "convenient", it is just a trick after all; And Dart provides a special interface
Future.microtask
to register microtasks:> /* JS */ | // Dart > function register(task){ | register(task){ > Promise.resolve.then( | Future.microtask( > task | task > ); | ); > } | }
Fortunately, in most cases, ordinary developers do not need to schedule task priorities by themselves, so this way of writing JS is irrelevant, as long as you don't drop the chain during the interview.
6. Promise
has more rich functions
Promise
who are familiar with 061628f7d6116d will not be unfamiliar with the static methodsPromise.allSettle
,Promise.race
,Promise.any
Future
, I hope to see them in Dart soon.JS finally got a game back!
Four. async/await
If you ask my favorite fromES6
which new features added since, that there is no doubtES2017
broughtasync/await
grammar andES2015
bring deconstruction syntax.
And in Dart,async/await
a magic weapon, is not absent!
7. Future
is the function provided by the dart:async
If you want to use
Future
(and), you should first introduce thedart:async
package.However, it can be used without introducing it in Dartpad.
Similarities
Basically similar in usage
Talk is cheap, here is the code:
> /* JS */ | // Dart > async function foo(){ | foo () async { > return await asyncFunc(); | return await asyncFunc(); > } | {
the difference
1. The location of the async
- In JS,
async
placed in front of the function declaration statement; In Dart,
async
placed at the end of the function parameter list.This difference has been reflected in the above example.
TODO: I need to study a little bit about where async
placed when the Dart constructor initializes instance variables. So the position summarized here is not necessarily correct.
2. Return Promise
and Future
- In JS,
async
function returnsPromise
instance; - In Dart, the
async
function returnsFuture
instance of 061628f7d613da.
The difference between the two types has been clarified in the previous section (at least the author thinks it is clarified), so I won't repeat it.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。