RQ
仅仅是一个文件,rq.js。运行起来创建一个 RQ
变量,该变量包含四个函数。
RQ
is delivered as a single file, rq.js. When run, it produces an RQ
variable containing an object containing four functions.
RQ.sequence
有一个请求者函数所构成的数组的参数,还有一个可选的参数,用于表示超时的。返回值是另一个总的请求者,它能够依次执行里面的每一个请求者,把上一个结果按照顺序地交给下一个。如果全体完成,那么最后一个请求者的结果将是全体的结果,以数组形式出现。如果数组中的一个请求者失败了,那么表示这个串行队列失败。数组并没有改变。
RQ.sequence
takes an array of requestor functions and an optional time limit in milliseconds. It returns a requestor function that will start each of the requestors in order, giving the result of each to the next one. If all complete successfully, the result will be the result of the last requestor in the array. If any of the requestors in the array fail, then the sequence fails. The array is not modified.
如果传入毫秒数的参数,则表示是超时的参数。
If a milliseconds argument is provided, then the sequence will fail if it does not finish before the time limit.
RQ.parallel
有一个必要请求者参数,为请求者函数所构成数组,及其用于表示超时的毫秒数参数(可选的),另外还有一个可选请求者参数(也是数组),及其用于表示超时的毫秒数参数(可选的)。该函数会返回另外一个总的请求者,会立刻执行必要请求者和可选请求者。结果为所有请求者的结果。如果有两个数组传入,结果数组的长度是那个传入数组总数之和。第一个请求者的结果就是结果数组中的第一个元素。整个并行任务完成与否取决于那些必要请求者,必要请求者成功了则成功。可选请求者的成功与否不会影响整个请求任务。这可用于最佳的尝试,从而获得了可以达成的结果。数组并没有改变。
RQ.parallel
takes an array of required requestor functions, and an optional time limit in milliseconds, and an optional array of optional requestors and an optional guaranteed time for the optional requestors. It returns a requestor function that will start all of the required and optional requestors at once. The result is an array containing all of the results from all of the requestors. If both arrays were provided, the length of the results array is the sum of the lengths of the two arrays. The result of the first requestor will be in the first position of the results array. The parallel will succeed only if all of the required requestors succeed. The array of optional requestors contains requests that can fail without causing the entire parallel operation to fail. It can be used as a best effort, obtaining the results that are attainable. The arrays are not modified.
如果提供了毫秒数的参数,那么表示在时限到来之前还没有完成请求的话,将宣告并行工作失败。缺省情况下(没有提供 untilliseconds),不管可选请求者怎么样,必要请求者完毕了可选请求者就完毕。如果提供了 untilliseconds 参数,就按照这个时限来对可选请求者限制。如果没有提供必要请求者,那么应该至少要传入一个可选请求者,并且在规定时限完成的话,这个并行就成功了。
If a milliseconds argument is provided, then the parallel will fail if all of the required requestors do not finish before the time limit. By default, the optionals have until all of the required requestors finish. The untilliseconds argument guarantees the optionals some amount of time. untilliseconds may not be larger than milliseconds. If the requireds array is empty, and if at least one optional requestor is successful within the allotted time, then the parallel succeeds.
RQ.parallel
并没有对 JavaScript 语言层面添加并行机制。它能让 JavaScript 程序充分利用语言层面原生的并行机制。程序自己并不是一脚包办所有事情,而且发出请求来让其他的进程或者机器来搞定事情,这些进程或者机器都是独立执行的。
RQ.parallel
does not add parallelism to JavaScript. It allows JavaScript programs to effectively exploit the inherent parallelism of the universe. It is likely that many of the requestors will be communicating with other processes and other machines. Those other processes and machines will be executing independently.
RQ.race
有一个请求者函数所构成的数组的参数,还有一个可选的参数,用于表示超时的。返回值是另一个总的请求者,它能够马上执行所有的请求者,但最终结果取得是最先成功的那次结果。如果数组中所有的请求者失败了,那么表示这个竞争失败。数组并没有改变。
如果传入毫秒数的参数,则表示是超时的参数。
If a milliseconds argument is provided, then the race will fail if it does not finish before the time limit.
RQ.fallback
有一个请求者函数所构成的数组的参数,还有一个可选的参数,用于表示超时的。返回值是另一个总的请求者,虽然它也会如串行般依次执行,但只要有一个请求者执行成功了,那么剩余的请求者将不会执行。如果数组中所有的请求者失败了,那么表示这个串行队列失败。数组并没有改变。
RQ.fallback
takes an array of requestor functions and an optional time limit in milliseconds. It returns a requestor function that will try each of the requestors in order until one is successful. If all of the requestors in the array fail, then the sequence fails. The array is not modified.
如果传入毫秒数的参数,则表示是超时的参数。
If a milliseconds argument is provided, then the fallback will fail if it does not finish before the time limit.
RQ
使用了四种类型的参数:requestors,callbacks,cancels和 factories。
RQ
makes use of four types of functions: requestors, callbacks, cancels, and factories.
请求者函数本身为函数类型,可表示某种任务。它可以是一个普通的函数,也可以是复杂的工作、任务或者操作,总之这些都是需要一定时间才能完成的工作,甚至也可以在多台机器上完成的。请求者函数有个两个参数,一个是回调函数,另外一个是可选值。请求者会对回调函数传入其结果并执行。可选值能够使之前的值按照顺序送入到请求者之中。
A requestor is a function that represents some unit of work. It can be a simple function, or it can be a complex job, task, production step, or operation that will organize the work of many machines over a long period of time. A requestor function takes two arguments: A callback and an optional value. The callback will be used by the requestor to communicate its result. The optional value makes the result of a previous value in a sequence to the requestor.
为了可以取消请求,请求者可以选择返回取消函数来取消请求。
A requestor may optionally return a cancel function that can be used to cancel the request.
回调函数就是送人到请求者的那个回调函数,可把请求者的值传入这个回调函数。回调函数有两个参数:成功或失败。若 failure 无意义,则代表请求者的请求成功了。
A callback is a function that is passed to a requestor so that the requestor can communicate its result. A callback can take two arguments, success and failure. If failure is falsy, then the requestor was successful.
当直接调用某个请求者时,你只需要传入一个回调函数,例如为了启动多个步骤的工作需要调用 RQ.sequence
的结果。这工作的结果将是传入到回调函数中的第一个参数。
You only have to provide a callback when calling a requestor directly, such as calling the result of RQ.sequence
to start a multistep job. The result of the job will be the first argument passed to your callback function.
取消函数是指会尝试停止请求者执行的函数。取消函数可以使流程中不再需要的任务停止。例如 RQ.race
启动了多个请求者,若其中一个请求者获得了成功,那么其余的请求者则不再需要执行,会被全部取消执行。取消函数既不能代表回滚(rollback),也不能代表后退(undo)。
A cancel is a function that will attempt to stop the execution of a requestor. A cancel function makes it possible to stop the processing of a job that is no longer needed. For example, if several requestors are started by RQ.race
and if one of the requestors produces an successful result, the results of the other requestors may be cancelled. Cancellation is intended to stop unnecessary work. Cancellation does not do rollbacks or undo.
取消函数可以由请求者返回。如果请求者对另外一个请求中的进程发出信息,那么取消函数应该要对同样那个进程发出消息,以告知那个进程不需要再工作了。
A cancel function may optionally be returned by a requestor. If a requestor sends a message to another process requesting work, the cancel function should send a message to the same process indicating that the work is no longer needed.
工厂函数就是生产请求者的函数。请求者的制定过程就是在工厂函数中利用那个参数完成的。RQ
提供的四个函数(RQ.sequence
、RQ.parallel
、RQ.race
、RQ.fallback
)皆是工厂函数。工厂函数能够简化程序开发。
A factory is a function that makes requestor functions. A factory will usually take arguments that allow for the customization of a requestor. The four functions provided by RQ
(RQ.sequence
, RQ.parallel
, RQ.race
, RQ.fallback
) are all factory functions. Factory functions can simplify application development.
有时候虽然能返回正确的结果,但如果太久的话那么也相当于是失败了。RQ 提供了一个可选的超时值来限制 requestor 进行的请求时间。如果请求者花太多时间来工作了,那么就应该要自动取消之。RQ.fallback
使得失败有所恢复。
Sometimes a correct result that takes too long is indistinguishable from a failure. RQ
provides optional timeout values that limit the amount of time that a requestor is allowed to take. If a requestor takes too long to do its work, it can be automatically cancelled. RQ.fallback
makes such failures recoverable.
identity_requestor
函数接收一个值并将其送到所传入的回调函数中。如果把 identity_requestor
放置于串行队列中,则仅仅是把前一个请求的结果交给下一个请求者。
The identity_requestor
receives a value and delivers that value to its callback. If the identity requestor is placed in a sequence, it acts as a nop, sending the result of the previous requestor to the next requestor.
function identity_requestor(callback, value) { return callback(value); }
全称请求者 fullname_requestor
接收一个对象,读取其身上的字符串属性,然后组成全称,最后将全称送到回调。
The fullname_requestor
receives an object and delivers a string made from properties of the object.
function fullname_requestor(callback, value) { return callback(value.firstname + ' ' + value.lastname); }
请求化工厂 requestorize
可以返回一个请求者函数。这里就是预先确定对回调函数参数的处理(译注:对要传入到 callback 的参数进行处理,处理过程在 func 中,在执行工厂函数时确定)。
The requestorize
factory can make a requestor from any function that takes a single argument.
function requestorize(func) { return function requestor(callback, value) { return callback(func(value)); }; }
我们可以利用该工厂函数生成序列中多个处理流程。例如,我们有下面这个函数,是根据一个对象来返回全称的:
We can use this to make processing steps in a sequence. For example, if we have a function that takes an object and returns a fullname:
function make_fullname(value) { return value.firstname + ' ' + value.lastname; }
那么我们接着可以将其转变为请求者,就像 fullname_requestor
:
We can turn it into a requestor that works just like the fullname_requestor
:
var fullname_requestor = requestorize(make_fullname);
请求者 delay_requestor
插入一个延时到串行中,非阻塞。
The delay_requestor
inserts a delay into a sequence without blocking.
function delay_requestor(callback, value) { var timeout_id = setTimeout(function () { return callback(value); }, 1000); return function cancel(reason) { return clearTimeout(timeout_id); }; }
真实请求者中,不是调用 setTimeout
, 而是一个消息将被发送到一个进程;而不是调用 clearTimeout
,而是一个消息将被发送到相同的进程以取消的工作。
In a real requestor, instead of calling setTimeout
, a message will be transmitted to a process, and instead of calling clearTimeout
, a message will be transmitted to the same process to cancel the work.
延时工厂就是返回延时请求者之用。
The delay
factory simplifies the making of delay requestors.
function delay(milliseconds) { return function requestor(callback, value) { var timeout_id = setTimeout(function () { return callback(value); }, milliseconds); return function cancel(reason) { return clearTimeout(timeout_id); }; }; }
构造工厂 construct
返回一个请求者,其参数是并行操作构成的数组另外,由于串行操作中需要对象结构的数据,所以亦安排了构造工作转换这个对象。
The construct
factory makes a requestor that takes an array of results from a parallel operation and converts it into an object for use by subsequent operations in a sequence.
function construct(array) { return function requestor(callback, value) { var object = Object.create(null); array.forEach(function (name, index) { object[name] = value[index]; }); return callback(object); }; }
虽然 buildPage
请求者采用了数组的结构,但我们可以使用对象格式的结构,这样的话,代码阅读起来会更能够自我描述(译注:更好读)。通过构造工厂 construct
实现更简单。
We could write our buildPage
requestor to take an array of values, but it makes more sense to give it an object so that its code will be self documenting. The construct
factory makes that easy.
respond = RQ.fallback([ RQ.sequence([ getId, getPreference, RQ.parallel([ getNav, RQ.race([ getAd(adnet.klikHaus), getAd(adnet.inUFace), getAd(adnet.trackPipe) ]), RQ.fallback([ fetch("weather", localCache), fetch("weather", localDB), fetch("weather", remoteDB) ]), getMessageOfTheDay ], [ getHoroscope, getGossip ], 50), construct(['nav', 'ads', 'weather', 'message', 'horoscope', 'gossip']), buildPage ], 100), planB ]};
执行 respond
发起请求,然后传入的回调函数将会接受最终值,getId
会最先得到值。
To start things running, call respond
, passing a callback function that will receive the final result, and the intial value that wll be given to getId
.