异步height:calc

This is a multi-part blog post series highlighting the capabilities of asynquence, a promises-based flow-control abstraction utility.

这是一个由多个部分组成的博客系列文章,重点介绍了异步的功能, 异步是一种基于Promise的流控制抽象实用程序。

  • Part 1: The Promises You Don't Know Yet

    第1部分:您尚不知道的承诺

  • Part 2: More Than Just Promises

    第2部分:不仅仅是承诺

on("before", start) (on("before", start))

Normally, my blog posts (and training workshops, for that matter!) are intended to teach something, and in the process I highlight projects that I've written to explore and experiment in that area. I find that to be an effective aid to teaching.

通常,我的博客文章(以及培训研讨会!)旨在教一些东西,在此过程中,我重点介绍我编写的旨在探索和试验该领域的项目。 我发现这是对教学的有效帮助。

However, this blog post series is going to be, unapologetically, quite a bit more obviously a promotion of one of my most important and ambitious projects: asynquence. The topic underlying? Promises and async flow-control.

但是,毫无疑问,这个博客文章系列将更加明显地促进我最重要,最雄心勃勃的项目之一: 异步 。 潜在的话题? 承诺和异步流控制。

But I've already written a detailed multi-part blog post series that teaches all about promises and the async issues they solve. I strongly suggest you read those posts first, if you're looking for deeper understanding of the topic, before you indulge my present ramblings on asynquence.

但是我已经写了一个详细的,由多个部分组成的博客文章系列 ,该系列文章全面介绍了Promise及其解决的异步问题。 如果您希望对本主题有更深入的了解,我强烈建议您先阅读这些文章,然后再沉迷于目前有关异步的话题

Why am I hard-promoting asynquence here in such an obvious self-horn-tooting way? Because I think it uniquely provides an accessibility to the topic of async flow-control and promises that you didn't realize you needed.

为什么我要以这种明显的自吹hard的方式在这里努力促进异步 ? 因为我认为它独特地提供了对异步流控制主题的可访问性,并保证您没有意识到自己的需要。

asynquence isn't rockstar popular or talked about by all the cool kids in-crowd. It doesn't have thousands of stars on github or millions of npm downloads. But I passionately believe if you spend some time digging into what it can do, and how it does it, you will find some missing clarity and relief from the tedium that sets in with other async utilities.

异步并不是摇滚明星中最受欢迎的,也不是所有酷炫的孩子们谈论的话题。 它在github上没有成千上万的星星,也没有数百万的npm下载。 但是我充满激情地相信,如果您花一些时间来研究它可以做什么以及如何去做 ,您会发现其他异步实用程序所带来的繁琐乏味。

This is a long post, and there's more than one post in this series. There's a whole lot to show off. Make sure to take some time to digest everything I'm about to show you. Your code will thank you... eventually.

这是一篇很长的文章,本系列中有多个。 有很多值得炫耀的地方。 确保花一些时间来消化我要向您展示的所有内容。 您的代码将最终谢谢您。

At a max size of well under 5k (minzipped) for everything (including optional plugins!), I think you'll see asynquence packs quite a punch for its modest byte count.

对于所有内容(包括可选插件!),最大大小都在5k以下 (最小压缩),我认为您会看到异步包对其适度的字节数产生了很大的冲击。

承诺还是抽象? (Promise Or Abstraction?)

The first thing to note is that despite some API similarities, asynquence creates an abstraction layer on top of promises, which I call sequences. That's where the weird name comes from: async + sequence = asynquence.

首先要注意的是,尽管API有一些相似之处,但异步在promise之上创建了一个抽象层,我将其称为sequence 。 那就是怪异名称的来源: async + sequence = asynquence

A sequence is a series of automatically created and chained promises. The promises are hidden under the API surface, so that you don't have to create or chain them in the general/simple cases. That's so that you can take advantage of promises with much less boilerplate cruft.

序列是一系列自动创建链接的承诺。 承诺被隐藏在API表面之下,因此您不必在一般/简单情况下创建或链接它们。 这样一来,您就可以以更少的样板内容利用承诺。

Of course, to make integration of asynquence into your project easier, a sequence can both consume a standard thenable/promise from some other vending, and it can also vend a standard ES6 promise at any step of a sequence. So you have ultimate freedom to sling promises around or enjoy the simplicity of the sequence abstractions.

当然,为了使异步轻松集成到您的项目中,序列既可以消耗其他自动售货中的标准可兑现/承诺,也可以在序列的任何步骤中出售标准ES6承诺。 因此,您有最终的自由来兑现承诺或享受序列抽象的简单性。

Each step of a sequence can be arbitrarily simple, like an immediately fulfilled promise, or arbitrarily complex, like a nested tree of sequences, etc. asynquence provides a wide array of abstraction helpers to invoke at each step, like gate(..) (the same as native Promises Promise.all(..)), which runs 2 or more "segments" (sub-steps) in parallel, and waits for all of them to complete (in any order) before proceeding on the main sequence.

序列的每个步骤可以任意简单,例如立即兑现的诺言;也可以任意复杂,例如序列的嵌套树,等等。 异步提供了广泛的抽象助手,可以在每个步骤调用,例如gate(..) (与本地Promises Promise.all(..)相同,后者并行运行2个或更多“段”(子步骤),并等待所有这些段(以任何顺序)完成后再继续执行主序列。

You construct the async flow-control expression for a particular task in your program by chaining together however many steps in the sequence as are applicable. Just like with promises, each step can either succeed (and pass along any number of success messages) or it can fail (and pass along any number of reason messages).

您可以通过将序列中的许多步骤适当地链接在一起,来为程序中的特定任务构造异步流控制表达式。 就像承诺一样,每个步骤可以成功(并传递任意数量的成功消息),也可以失败(并传递任意数量的原因消息)。

In this blog post, I detail a whole host of limitations implied when all you have are promises, and make the case for the power and utility of abstractions. I make the claim there that asynquence frees you from all these limitations, so this blog post series proves such a claim.

在这篇博客文章中 ,我详细介绍了当您拥有全部承诺时隐含的全部限制,并说明了抽象的强大功能和实用性。 我在那里声称异步可以使您摆脱所有这些限制,因此本博客系列证明了这种主张。

基本 (Basics)

You're certainly more interested in seeing code than reading me ramble on about code. So, let's start by illustrating the basics of asynquence:

与阅读有关代码的闲逛相比,您当然对查看代码更感兴趣。 因此,让我们从说明异步的基础开始

ASQ(function step1(done){
setTimeout(function(){
done( "Hello" );
},100);
})
.then(function step2(done,msg){
setTimeout(function(){
done( msg.toUpperCase()) ;
},100);
})
.gate(
// these two segments '3a' and '3b' run in parallel!
function step3a(done,msg) {
setTimeout(function(){
done( msg + " World" );
// if you wanted to fail this segment,
// you would call `done.fail(..)` instead
},500);
},
function step3b(done,msg) {
setTimeout(function(){
done( msg + " Everyone" );
},300);
}
)
.then(function step4(done,msg1,msg2){
console.log(msg1,msg2); // "Hello World"  "Hello Everyone"
})
.or(function oops(err){
// if any error occurs anywhere in the sequence,
// you'll get notified here
});

With just that snippet, you see a pretty good depiction of what asynquence was originally designed to do. For each step, a promise is created for you, and you are provided with the trigger (which I like to always call done for simplicity), which you just need to call now or at some point later.

仅使用该代码段,您就可以很好地描述最初设计异步的目的。 对于每个步骤,都会为您创建一个承诺,并且会为您提供触发器(为简单起见,我经常将其称为“ done ”),您只需要现在或稍后调用即可。

If an error occurs, or if you want to fail a step by calling done.fail(..), the rest of the sequence path is abandoned and any error handlers are notified.

如果发生错误,或者您想通过调用done.fail(..)来使步骤失败,则序列路径的其余部分将被放弃,并通知所有错误处理程序。

错误不丢失 (Errors Not Lost)

With promises, if you fail to register an error handler, the error stays silently buried inside the promise for some future consumer to observe. This along with how promise-chaining works leads to all manner of confusion and nuance.

使用promise,如果您未能注册错误处理程序,则错误会静默地隐藏在promise中,以供将来的某些使用者观察。 这与承诺链的工作 方式一起导致各种混乱和细微差别 。

If you read those discussions, you'll see I make the case that promises have an "opt-in" model for error handling, so if you forget to opt-in, you fail silently. This is what we disaffectionately call a "pit of failure".

如果您阅读了这些讨论,您会发现我认为Promise具有用于错误处理的“选择加入”模型,因此,如果您忘记选择加入,则会无声无息地失败。 这就是我们不以为然的“失败之坑”

asynquence reverses this paradigm, creating a "pit of success". The default behavior of a sequence is to report any error (intentional or accidental) in a global exception (in your dev console), rather than swallow it. Of course, reporting it in a global exception doesn't erase the sequences's state, so it can still be programmatically observed later as usual.

异步使这种范式逆转,创造了“成功之 。 序列的默认行为是在全局异常中(在您的开发控制台中)报告任何错误(有意或无意),而不是吞下它。 当然,在全局异常中报告它不会删除序列的状态,因此以后仍然可以像往常一样以编程方式对其进行观察。

You can "opt-out" of this global error reporting in one of two ways: (1) register at least one or error handler on the sequence; (2) call defer() on the sequence, which signals that you intend to register an error handler later.

您可以通过以下两种方式之一“选择退出”此全局错误报告:(1)在序列上至少注册一个or错误处理程序; (2)在序列上调用defer() ,这表示您打算稍后注册错误处理程序。

Furthermore, if sequence A is consumed by (combined into) another sequence B, A.defer() is automatically called, shifting the error handling burden to B, just like you'd want and expect.

此外,如果序列A被另一个序列B占用(组合), A.defer()自动调用A.defer() ,将错误处理负担转移到B上 ,就像您想要和期望的那样。

With promises, you have to work hard to make sure you catch errors, and if you fall short, you'll be confused as they'll be hidden in subtle, hard-to-find ways. With asynquence sequences, you have to work hard to NOT catch errors. asynquence makes your error handling easier and saner.

有了承诺,您就必须努力确保发现错误,如果您未能兑现错误,您会感到困惑,因为它们将以微妙的,难以发现的方式被隐藏。 对于异步序列,您必须努力工作以捕获错误。 异步使您的错误处理更加轻松和合理。

留言内容 (Messages)

With promises, the resolution (success or failure) can only happen with one distinct value. It's up to you to wrap multiple values into a container (object, array, etc) should you need to pass more than one value along.

有了承诺,解决方案(成功或失败)只能以一种不同的价值来实现。 如果您需要传递多个值,则取决于您将多个值包装到一个容器(对象,数组等)中。

asynquence assumes you need to pass any number of parameters (either success or failure), and automatically handles the wrapping/un-wrapping for you, in the way you'd most naturally expect:

异步假定您需要传递任意数量的参数(成功或失败),并以您最自然希望的方式为您自动处理包装/展开:

ASQ(function step1(done){
done( "Hello", "World" );
})
.then(function step2(done,msg1,msg2){
console.log(msg1,msg2); // "Hello"  "World"
});

In fact, messages can easily be injected into a sequence:

实际上,可以轻松地将消息注入到序列中:

ASQ( "Hello", "World" )
.then(function step1(done,msg1,msg2){
console.log(msg1,msg2); // "Hello"  "World"
})
.val( 42 )
.then(function(done,msg){
console.log(msg); // 42
});

In addition to injecting success messages into a sequence, you can also create an automatically failed sequence (that is, messages that are error reasons):

除了将成功消息注入到序列中之外,您还可以创建自动失败的序列(即,由于错误原因引起的消息):

// make a failed sequence!
ASQ.failed( "Oops", "My bad" )
.then(..) // will never run!
.or(function(err1,err2){
console.log(err1,err2); // "Oops"  "My bad"
});

停止问题 (Halting Problem)

With promises, if you have say 4 promises chained, and at step 2 you decide you don't want 3 and 4 to occur, you're only option is to throw an error. Sometimes this makes sense, but more often it's rather limiting.

使用promise,如果您说有4个promise连锁,而在第2步中您决定不希望出现3和4,则唯一的选择就是抛出一个错误。 有时候这是有道理的,但更多时候是相当有限的。

You'd probably like to just be able to cancel any promise. But, if a promise itself can be aborted/canceled from the outside, that actually violates the important principle of trustably externally immutable state.

您可能只想取消任何承诺即可。 但是,如果一个承诺本身可以从外部中止/取消,则实际上违反了可信赖的外部不可变状态的重要原则 。

var sq = ASQ(function step1(done){
done(..);
})
.then(function step2(done){
done.abort();
})
.then(function step3(done){
// never called
});
// or, later:
sq.abort();

Aborting/canceling shouldn't exist at the promise level, but in the abstraction on layer on top of them. So, asynquence lets you call abort() on a sequence, or at any step of a sequence on the trigger. To the extent possible, the rest of the sequence will be completely abandoned (side effects from async tasks cannot be prevented, obviously!).

中止/取消不应在承诺级别存在,而应在它们之上的抽象层中存在。 因此, 异步使您可以在序列上或触发器的序列的任何步骤上调用abort() 。 在可能的情况下,该序列的其余部分将被完全放弃(显然,无法避免异步任务带来的副作用!)。

同步步骤 (Sync Steps)

Despite much of our code being async in nature, there are always tasks which are fundamentally synchronous. The most common example is performing a data extraction or transformation task in the middle of a sequence:

尽管我们的许多代码本质上都是异步的,但总有一些任务基本上是同步的。 最常见的示例是在序列中间执行数据提取或转换任务:

ASQ(function step1(done){
done( "Hello", "World" );
})
// Note: `val(..)` doesn't receive a trigger!
.val(function step2(msg1,msg2){
// sync data transformation step
// `return` passes sync data messages along
// `throw` passes sync error messages along
return msg1 + " " + msg2;
})
.then(function step3(done,msg){
console.log(msg); // "Hello World"
});

The val(..) step method automatically advances the promise for that step after you return (or throw for errors!), so it doesn't pass you a trigger. You use val(..) for any synchronous step in the middle of the sequence.

val(..)步骤方法在您return (或throw错误!)之后会自动推进该步骤的承诺,因此不会为您传递触发器。 您可以将val(..)用于序列中间的任何同步步骤。

回呼 (Callbacks)

Especially in node.js, (error-first style) callbacks are the norm, and promises are the new kid on the block. This means that you'll almost certainly be integrating them into your async sequences code. When you call some utility that expects an error-first style callback, asynquence provides errfcb() to create one for you, automatically wired into your sequence:

尤其是在node.js中,(错误优先型)回调是常见的,而promises是新手。 这意味着您几乎可以肯定会将它们集成到异步序列代码中。 当您调用某个需要错误优先样式回调的实用程序时, 异步提供errfcb()为您创建一个,并自动连接到您的序列中:

ASQ(function step1(done){
// `done.errfcb` is already an error-first
// style callback you can pass around, just like
// `done` and `done.fail`.
doSomething( done.errfcb );
})
.seq(function step2(){
var sq = ASQ();
// calling `sq.errfcb()` creates an error-first
// style callback you can pass around.
doSomethingElse( sq.errfcb() );
return sq;
})
.then(..)
..

Note: done.errfcb and sq.errfcb() differ in that the former is already created so you don't need to () invoke it, whereas the latter needs to be called to make a callback wired to the sequence at that point.

注意: done.errfcbsq.errfcb()不同之处在于,已经创建了前者,因此您无需()调用它,而此时需要调用后者以使回调连接到序列。

Some other libraries provide methods to wrap other function calls, but this seems too intrusive for asynquence's design philosophy. So, to make a sequence-producing method wrapper, make your own, like this:

其他一些库提供了包装其他函数调用的方法,但是对于异步设计原理而言,这似乎太麻烦了。 因此,要制作一个序列生成方法包装器,请自己制作,如下所示:

// in node.js, using `fs` module,
// make a suitable sequence-producing
// wrapper for `fs.write(..)`
function fsWrite(filename,data) {
var sq = ASQ();
fs.write( filename, data, sq.errfcb() );
return sq;
}
fsWrite( "meaningoflife.txt", "42" )
.val(function step2(){
console.log("Phew!");
})
.or(function oops(err){
// file writing failed!
});

承诺,承诺 (Promises, Promises)

asynquence should be good enough at async flow-control that for nearly all your needs, it's all the utility you need. But the reality is, promises themselves will still show up in your program. asynquence makes it easy to go from promise to sequence to promise as you see fit.

异步在异步流控制方面应该足够好,几乎可以满足您的所有需求,这就是您需要的所有实用程序。 但是现实是,承诺自己仍然会出现在您的程序中。 异步使您可以轻松地从承诺到序列再到承诺。

var sq = ASQ()
.then(..)
.promise( doTaskA() )
.then(..)
..
// doTaskB(..) requires you to pass
// a normal promise to it!
doTaskB( sq.toPromise() );

promise(..) consumes one or more standard thenables/promises vended from elsewhere (like inside doTaskA()) and wires it into the sequence. toPromise() vends a new promise forked from that point in the sequence. All success and error message streams flow in and out of promises exactly as you'd expect.

promise(..)消耗了从其他地方(如doTaskA()内部doTaskA()出售的一个或多个标准的可兑现/承诺,并将其连接到序列中。 toPromise()为序列中从该点分叉的新承诺提供了保证。 所有成功和错误消息流都完全按照您的期望流入和流出承诺。

序列+序列 (Sequences + Sequences)

The next thing you'll almost certainly find yourself doing regularly is creating multiple sequences and wiring them together.

您几乎肯定会发现自己定期做的下一件事是创建多个序列并将它们连接在一起。

For example:

例如:

var sq1 = doTaskA();
var sq2 = doTaskB();
var sq3 = doTaskC();
ASQ()
.gate(
sq1,
sq2
)
.then( sq3 )
.seq( doTaskD )
.then(function step4(done,msg){
// Tasks A, B, C, and D are done
});

sq1 and sq2 are separate sequences, so they can be wired directly in as gate(..) segments, or as then(..) steps. There's also seq(..) which can either accept a sequence, or more commonly, a function that it will call to produce a sequence. In the above snippet, function doTaskD(msg1,..) { .. return sq; } would be the general signature. It receives the messages from the previous step (sq3), and is expected to return a new sequence as step 3.

sq1sq2是独立的序列,因此可以将它们直接连接为gate(..)段或then(..)步骤。 还有seq(..)可以接受序列,或更常见的是,它将调用该函数来产生序列。 在以上代码段中, function doTaskD(msg1,..) { .. return sq; } function doTaskD(msg1,..) { .. return sq; }将是一般签名。 它从上一步( sq3 )接收消息,并期望在步骤3中返回新序列。

Note: This is another API sugar where asynquence can shine, because with a promise-chain, to wire in another promise, you have to do the uglier:

注意:这是异步可以发光的另一个API糖,因为要使用诺言链连接另一个诺言,您必须做得更难看:

pr1
.then(..)
.then(function(){
return pr2;
})
..

As seen above, asynquence just accepts sequences directly into then(..), like:

如上所示, 异步仅将序列直接接受到 then(..) ,例如:


sq1
.then(..)
.then(sq2)
..

Of course, if you find yourself needing to manually wire in a sequence, you can do so with pipe(..):

当然,如果您发现需要按顺序手动接线,则可以使用pipe(..)进行接线:

ASQ()
.then(function step1(done){
// pipe the sequence returned from `doTaskA(..)`
// into our main sequence
doTaskA(..).pipe( done );
})
.then(function step2(done,msg){
// Task A succeeded
})
.or(function oops(err){
// errors from anywhere, even inside of the
// Task A sequence
});

As you'd reasonably expect, in all these variations, both success and error message streams are piped, so errors propagate up to the outermost sequence naturally and automatically. That doesn't stop you from manually listening to and handling errors at any level of sub-sequence, however.

如您合理预期的那样,在所有这些变体中,成功流和错误消息流都通过管道传输,因此错误自然而然地传播到最外层序列。 但是,这并不能阻止您手动侦听和处理任何子序列级别的错误。

ASQ()
.then(function step1(done){
// instead of `pipe(..)`, manually send
// success message stream along, but handle
// errors here
doTaskA()
.val(done)
.or(function taskAOops(err){
// handle Task A's errors here only!
});
})
.then(function step2(done,msg){
// Task A succeeded
})
.or(function oops(err){
// will not receive errors from Task A sequence
});

叉子>勺子 (Forks > Spoons)

You may need to split a single sequence into two separate paths, so fork() is provided:

您可能需要将单个序列分成两个单独的路径,因此提供了fork()

var sq1 = ASQ(..).then(..)..;
var sq2 = sq1.fork();
sq1.then(..)..; // original sequence
sq2.then(..)..; // separate forked sequence

In this snippet, sq2 won't proceed as its separate forked sequence until the pre-forked sequence steps complete (successfully).

在此代码段中,直到预分叉的序列步骤(成功)完成后, sq2才作为其单独的分叉序列继续进行。

含糖抽象 (Sugary Abstractions)

OK, that's what you need to know about the foundational core of asynquence. While there's quite a bit of power there, it's still pretty limited compared to the feature lists of utilities like "Q" and "async". Fortunately, asynquence has a lot more up its sleeve.

好的,这就是您需要了解的异步基础。 尽管这里有很多功能,但是与“ Q”和“ async”之类的实用程序的功能列表相比,它仍然非常有限。 幸运的是, 异步性有很多不足之处

In addition to the asynquence core, you can also use one or many of the provided asynquence-contrib plugins, which add lots of tasty abstraction helpers to the mix. The contrib builder lets you pick which ones you want, but builds all of them into the contrib.js package by default. In fact, you can even make your own plugins quite easily, but we'll discuss that in the next post in this series.

除了异步核心之外,您还可以使用一个或多个提供的异步contrib插件,这些插件为混合添加了许多美味的抽象助手。 contrib构建器使您可以选择所需的构建器,但默认情况下contrib.js其全部构建到contrib.js包中。 实际上,您甚至可以非常轻松地制作自己的插件,但是我们将在本系列的下一篇文章中进行讨论。

门的变化 (Gate Variations)

There are 6 simple variations to the core gate(..) / all(..) functionality provided as contrib plugins: any(..), first(..), race(..), last(..), none(..), and map(..).

作为contrib插件提供的核心gate(..) / all(..)功能有6种简单的变体: any(..)first(..)race(..)last(..)none(..)map(..)

any(..) waits for all segments to complete just like gate(..), but only one of them has to be a success for the main sequence to proceed. If none succeed, the main sequence is set to error state.

any(..)gate(..)一样等待所有段完成,但是只有一个成功执行主序列才能成功。 如果没有成功,则将主序列设置为错误状态。

first(..) waits only for the first successful segment before the main sequence succeeds (subsequent segments are just ignored). If none succeed, the main sequence is set to error state.

first(..)在主序列成功之前仅等待第一个成功的段(随后的段将被忽略)。 如果没有成功,则将主序列设置为错误状态。

race(..) is identical in concept to native Promise.race(..), which is kind of like first(..), except it's racing for the first completion regardless of success or failure.

race(..)在概念上与本机Promise.race(..) ,后者类似于first(..) ,除了无论成功与否,它都在争取第一个完成。

last(..) waits for all segments to complete, but only the latest successful segment's success messages (if any) are sent along to the main sequence to proceed. If none succeed, the main sequence is set to error state.

last(..)等待所有段完成,但是只有最新成功段的成功消息(如果有)被发送到主序列以继续。 如果没有成功,则将主序列设置为错误状态。

none(..) waits for all segments to complete. It then transposes success and error states, which has the effect that the main sequence proceeds only if all segments failed, but is in error if any or all segments succeeded.

none(..)等待所有段完成。 然后,它转置成功和错误状态,其结果是,仅当所有段都失败时,主序列才继续执行,但如果有任何或所有段成功,则主序列才出错。

map(..) is an asynchronous "map" utility, much like you'll find in other libraries/utilities. It takes an array of values, and a function to call against each value, but it assumes the mapping may be asynchronous. The reason it's listed as a gate(..) variant is that it calls all mappings in parallel, and waits for all to complete before it proceeds. map(..) can have either the array or the iterator callback or both provided to it directly, or as messages from the previous main sequence step.

map(..)是一个异步“地图”实用程序,就像您在其他库/实用程序中会发现的一样。 它需要一个值数组和一个针对每个值进行调用的函数,但是它假定映射可能是异步的。 之所以将其列为gate(..)变体,是因为它并行调用所有映射,并等待所有映射完成才继续进行。 map(..)可以具有数组或迭代器回调,也可以直接提供给它们,也可以作为来自上一个主序列步骤的消息来提供。

ASQ(function step1(done){
setTimeout(function(){
done( [1,2,3] );
});
})
.map(function step2(item,done){
setTimeout(function(){
done( item * 2 );
},100);
})
.val(function(arr){
console.log(arr); // [2,4,6]
});

阶跃变化 (Step Variations)

Other plugins provide variations on normal step semantics, such as until(..), try(..), and waterfall(..).

其他插件提供了常规步骤语义的变体,例如until(..)try(..)waterfall(..)

until(..) keeps re-trying a step until it succeeds, or you call done.break() from inside it (which triggers error state on the main sequence).

until(..)一直重试步骤直到成功为止,或者您从步骤内部调用done.break() (这会在主序列上触发错误状态)。

try(..) attempts a step, and proceeds with success on the sequence regardless. If an error/failure is caught, it passes forward as a special success message in the form { catch: .. }.

try(..)尝试执行一个步骤,然后无论如何都成功执行序列。 如果发现错误/失败,它将作为特殊成功消息以{ catch: .. }形式转发。

waterfall(..) takes multiple steps (like that would be provided to then(..) calls), and processes them in succession. However, it cascades the success message(s) from each step into the next, such that after the waterfall is complete, all success messages are passed along to the subsequent step. It saves you having to manually collect and pass them along, which can be quite tedious if you have many steps to waterfall.

waterfall(..)采取多个步骤(就像将提供给then(..)调用一样),并连续处理它们。 但是,它将每个步骤中的成功消息级联到下一个步骤,以便在完成瀑布之后,所有成功消息都将传递到后续步骤。 这省去了您手动收集和传递它们的麻烦,如果您要执行许多瀑布操作,这将非常繁琐。

高阶抽象 (Higher Order Abstractions)

Any abstraction that you can dream up can be expressed as a combination of the above utilities and abstractions. If you have a common abstraction you find yourself doing regularly, you can make it repeatably usable by putting it into its own plugin (again, covered in the next post).

您可以梦想的任何抽象都可以表示为上述实用程序和抽象的组合。 如果您有一个常见的抽象概念,并且发现自己经常做,可以通过将其放入自己的插件中来使其可重复使用(同样, 在下一篇文章中介绍 )。

One example would be providing timeouts for a sequence, using race(..) (explained above) and the failAfter(..) plugin (which, as it sounds, makes a sequence that fails after a specified delay):

一个示例是使用race(..) (如上所述)和failAfter(..)插件(听起来像是使序列在指定的延迟后失败race(..)提供序列超时:

ASQ()
.race(
// returns a sequence for some task
doSomeTask(),
// makes a sequence that will fail eventually
ASQ.failAfter( 2000, "Timed Out!" )
)
.then(..)
.or(..);

This example sets up a race between a normal sequence and an eventually-failing sequence, to provide the semantics of a timeout limit.

此示例在正常序列和最终失败序列之间建立了竞争,以提供超时限制的语义。

If you found yourself doing that regularly, you could easily make a timeoutLimit(..) plugin for the above abstraction (see the next post).

如果您发现自己定期执行此操作,则可以轻松地为上述抽象制作一个timeoutLimit(..)插件(请参阅下一篇文章 )。

功能(阵列)操作 (Functional (Array) Operations)

All the above examples have made one fundamental assumption, which is that you know ahead of time exactly what your flow-control steps are.

以上所有示例均做出了一个基本假设,即您提前知道流量控制步骤是什么。

Sometimes, though, you need to respond to a varying amount of steps, such as each step representing a resource request, where you may need to request 3 or 30.

但是,有时您需要响应不同数量的步骤,例如代表资源请求的每个步骤,其中您可能需要请求3或30。

Using some very simple functional programming operations, like Array map(..) and reduce(..), we can easily achieve this flexibility with promies, but you'll find that the API sugar of asynquence makes such tasks even nicer.

使用一些非常简单的函数式编程操作(例如Array map(..)reduce(..) ,我们可以轻松地通过Promies实现这种灵活性,但是您会发现, 异步的API糖使此类任务变得更好

Note: If you don't know about map/reduce yet, you're going to want to spend some time (should only take a few hours tops) learning them, as you will find their usefulness all over promises-based coding!

注意:如果您还不了解map / reduce,那么您将需要花费一些时间(应该只花几个小时的时间)来学习它们,因为您会发现它们在基于promise的编码中很有用!

功能实例 (Functional Example)

Let's say you want to request 3 (or more) files in parallel, render their contents ASAP, but make sure they still render in natural order. If file1 comes back before file2, render file1 right away. If file2 comes back first, though, wait until file1 and then render both.

假设您要并行请求3个(或更多)文件,尽快渲染其内容,但要确保它们仍以自然顺序渲染。 如果file1在file2之前返回,则立即渲染file1。 但是,如果file2首先返回,请等到file1然后再渲染两者。

Here's how you can do that with normal promises (we'll ignore error handling for simplification purposes):

这是使用常规诺言来实现的方式(为简化起见,我们将忽略错误处理):

function getFile(file) {
return new Promise(function(resolve){
ajax(file,resolve);
});
}
// Request all files at once in "parallel" via `getFile(..)`
[ "file1", "file2", "file3" ]
.map(getFile)
.reduce(
function(chain,filePromise){
return chain
.then(function(){
return filePromise;
})
.then(output);
},
Promise.resolve() // fulfilled promise to start chain
)
.then(function() {
output("Complete!");
});

Not too bad, if you parse what's happening with map(..) and then reduce(..). The map(..) call turns an array of strings into an array of promises. The reduce(..) call "reduces" the array of promises into a single chain of promises that will perform the steps in order as required.

不错,如果您解析map(..)发生了什么,然后reduce(..)map(..)调用将字符串数组转换为Promise数组。 reduce(..)调用将promise数组“ reduce(..) ”为单个promise链,该promise链将按要求顺序执行步骤。

Now, let's look at how asynquence can do the same task:

现在,让我们看一下异步如何完成相同的任务:

function getFile(file) {
return ASQ(function(done){
ajax(file,done);
});
}
ASQ()
.seq.apply(null,
[ "file1", "file2", "file3" ]
.map(getFile)
.map(function(sq){
return function(){
return sq.val(output);
};
})
)
.val(function(){
output("Complete!");
});

Note: These are sync map calls, so there's no real benefit to using asynquence's async map(..) plugin discussed earlier.

注意:这些是同步映射调用,因此使用前面讨论的asynquence的async map(..)插件并没有真正的好处。

Owing to some of the API sugar of asynquence, you can see we don't need reduce(..), we just use two map(..) calls. The first turns the array of strings into an array of sequences. The second turns the array of sequences into an array of functions which each return a sub-sequence. This second array is sent as parameters to the seq(..) call in asynquence, which processes each sub-sequence in order.

由于异步的一些API 优势 ,您可以看到我们不需要reduce(..) ,我们只使用了两个map(..)调用。 第一个将字符串数组转换为序列数组。 第二个将序列数组转换为函数数组,每个函数返回一个子序列。 第二个数组作为参数发送给seq(..) 异步调用,该调用按顺序处理每个子序列。

Easy as cake, right?

像蛋糕一样容易 ,对吗?

.summary(..) (.summary(..))

I think by now, if you've read this far, asynquence is speaking for itself. It's powerful, but it's also very terse and distinctly lacking in boilerplate cruft, compared to other libraries and especially compared to native promises.

我认为,到目前为止,如果您已经读过这篇文章, 那么异步就可以说明一切。 它功能强大,但与其他库相比,尤其是与本机Promise相比,它非常简洁并且明显缺乏样板文件。

It's also extensible (with plugins, as the next post will cover), so you have virtually no limits to what you can make it do for you.

它也是可扩展的(带有插件,正如下一篇文章将介绍的那样),因此您几乎可以为自己做些什么。

I hope you are convinced to at least give asynquence a try, now.

我希望您确信现在至少可以尝试一下异步

But if promise abstraction and API sugar was all asynquence had to offer, it might not obviously outshine its much more well-known peers. The next post will go way beyond promises into some much more advanced async capabilities. Let's find out just how deep the rabbit hole goes.

但是,如果必须提供承诺抽象和API糖,那么它可能显然不胜过其更为知名的同行。 下一篇文章将超越承诺,提供一些更高级的异步功能。 让我们找出兔子洞的深度。

翻译自: https://davidwalsh.name/asynquence-part-1

异步height:calc


http://www.taodudu.cc/news/show-5704680.html

相关文章:

  • 千凿万击,一声小度
  • 什么是显式promise构造反模式,如何避免呢?
  • python集合操作班级干部竞选演讲稿_关于竞选班干部演讲稿集合五篇
  • 如何处理嵌套的回调并避免“回调地狱”
  • 百度真到了“拐点时刻”?
  • 未来的全能保姆机器人作文_保姆机器人作文400字
  • ES6语法 学习
  • 制作网页常用布局
  • 动漫市场硝烟再起:优酷、爱奇艺、腾讯三方如何互掐?
  • 为什么中国做不出《旅行青蛙》这样的游戏?
  • xgp游戏列表_多款游戏即将加入XGP 包含实况足球2020、全境封锁等
  • 华为手机升级回退_EMUI4.0回退EMUI3.1!通过华为手机助手也能实现
  • Mac笔记本安装Gradle
  • Gradle 构建环境变量配置
  • gradle介绍,简单易学
  • Gradle 详解
  • 基于SpringBoot和React的在线考试平台
  • 强力删除小程序
  • win10 shell360ext.dll删除
  • 比360都好用的删除文件方式
  • 硬盘文件无法删除(360强力删除无效)的解决方法
  • 连环画《秦王斩荆柯》|大象特供
  • WebGL 动画
  • 1.6万亿参数你怕了吗?谷歌大脑发布语言模型 Switch Transformer,速度碾压T5
  • 安卓下实现排序算法动画
  • 天才大象画画
  • python画大象_Python Day4-5
  • python画大象_Python学习之路(01)-- Python基础
  • python画大象_Python Day18
  • python画大象_Python Day8

异步height:calc_异步:您尚不知道的承诺(第1部分)相关推荐

  1. 异步height:calc_异步:不仅仅是承诺(第二部分)

    异步height:calc This is a multi-part blog post series highlighting the capabilities of asynquence, a p ...

  2. 你所不知道的日志异步落库

    https://www.cnblogs.com/scy251147/p/9193075.html 在互联网设计架构过程中,日志异步落库,俨然已经是高并发环节中不可缺少的一环.为什么说是高并发环节中不可 ...

  3. C#~异步编程再续~你必须要知道的ThreadPool里的throw

    问题依旧存在 之前写过相关文章异步编程的文章,本文主要还是一点补充,之前在IIS经常发w3wp进程无做挂了的情况,但一直没能找到真正的原因,而查找相关资料,找了一些相关的文章,如await和async ...

  4. ES6 你可能不知道的事 – 基础篇

    ES6 你可能不知道的事 – 基础篇 转载 作者:淘宝前端团队(FED)- 化辰 链接:taobaofed.org/blog/2016/07/22/es6-basics/ 序 ES6,或许应该叫 ES ...

  5. 考csp所需算法_CSP vs RxJS:您所不知道的。

    考csp所需算法 by Kevin Ghadyani 通过凯文·加迪亚尼(Kevin Ghadyani) CSP vs RxJS:您所不知道的. (CSP vs RxJS: what you don' ...

  6. javascript迭代器_JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释...

    javascript迭代器 by rajaraodv 通过rajaraodv JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释 (JavaScript Symbols, ...

  7. 「从源码中学习」面试官都不知道的Vue题目答案

    前言 当回答面试官问及的Vue问题,我们除了照本宣科的回答外,其实还可以根据少量的源码来秀一把,来体现出你对Vue的深度了解. 本文会陆续更新,此次涉及以下问题: "new Vue()做了什 ...

  8. 80%开发者都不知道的以太坊骚操作:「事件」和「日志」还可以这么玩!

    80%开发者都不知道的以太坊骚操作:「事件」和「日志」还可以这么玩! 2018年05月02日 00:00:00 阅读数:366 作者 | 蔡一  志顶科技技术总监 4月6日,Daniel Larime ...

  9. 你绝对不知道的head标签

    你绝对不知道的head标签 先来梳理一下本文的目录结构 现在我将详解head标签和它六个子标签的属性和作用,请耐心看完,会有很大的收获哦! 一.head标签 可选属性: 属性 值 描述 profile ...

最新文章

  1. stick footers布局
  2. LightGBM如何保存模型?
  3. 使用ViewContainerRef探索Angular DOM操作技术
  4. 远程管理服务器的具体操作方法
  5. 2013年5月16日星期四初始sqlserver附加数据库权限及maven和selenium
  6. 熟悉的指标,多重的应用
  7. hdu 5411 CRB and Puzzle 矩阵高速幂
  8. 使用vue+elementUI+springboot创建基础后台增删改查的管理页面--(1)
  9. ftp服务器不能读取文件内容_使用file_get_contents()函数读取文件内容
  10. stm32的rxcallback再debug界面显示没有编译,uC/OS-III
  11. mysql load data infile 上传数据 不显示_第22问:我有带外键的表,你有数据么?
  12. java基础-软件简述
  13. SQL学习03---数据库系统概念第6版第3章习题答案
  14. Mac OS X 10.2 (Macintosh)的101个应用技巧(转)
  15. 或是独体字吗_独体字
  16. 2022年《财富》世界500强企业
  17. js实现鼠标悬浮图片放大预览
  18. 基于python的json脚本解析
  19. python爬虫--Scrapy框架--Scrapy+selenium实现动态爬取
  20. sql --Acess

热门文章

  1. python画素描画_python如何将图片转换素描画
  2. pptp服务器 虚拟机,pptp服务器设置方法
  3. Ijkplayer直播App卡顿问题分析
  4. dom4j 解析 xml 为 Java 对象
  5. MacOS 抓包工具Fiddler Everywhere:安装与使用
  6. 腾讯、网易纷纷出手,火到出圈的元宇宙到底是个啥?
  7. 《动手学深度学习》课后习题3
  8. otter,阿里巴巴分布式数据库同步系统
  9. java多线程批量更新数据库的数据
  10. maven安装及配置(超详细)