【问题标题】:What is the idiom for optional asynchronous preprocessing in Javascript?Javascript中可选异步预处理的习惯用法是什么?
【发布时间】:2016-11-22 18:13:32
【问题描述】:

假设我必须进行一些计算,例如包括计算 A(异步,使用回调),然后在计算 A 时,计算 B(也使用回调异步)。

问题是A是可选的,如果没有数据,我应该直接计算B。

目前我使用非常丑陋的代码,B 执行加倍,如下所示:

if (A)
  computeA(A,() => computeB(B,() => console.log("done.")));
else
  computeB(B,() => console.log("done."));

我要求避免烘烤一些我的解决方案,这不会被任何 JS 开发人员识别 :-) 它有一些成语吗?

【问题讨论】:

标签: javascript asynchronous idioms


【解决方案1】:

这也可以通过 Promise 轻松完成:

if (A)
   p = A();
else
   p = Promise.resolve(defaultValue)

p.then(B).then(done)

假设 A 和 B 都返回承诺。如果他们是传统的回调接受者,你必须承诺他们。

【讨论】:

  • 太棒了!我希望有这样的表格,所以非常感谢。
  • 酷。在原始问题中可以使用 Promises 并不明显。这是一个更好的答案。
  • @naomik,你为什么删除你的答案?这很好!拜托,你能把它放回去吗——当你需要把踏板踩到金属上时,放弃任何分配都是一件很有价值的事情。
【解决方案2】:

这本质上是延续传球风格。因为延续只是一个函数,你可以将总是发生的链分配给一个var,然后在if的每个分支中重用它

let next = () => computeB(B,() => console.log("done."))
if (A)
  computeA(A, next)
else
  next()

一个小小的延续单子

在 JavaScript 中使用延续非常有趣,它们以非常有意义的方式表达特定问题。

这是延续单子cont 的一个小实现,它允许您定义您希望在计算中链接的各种函数。

when 是这里的关键函数,因为它允许您指定一个有条件地绑定链中另一个函数的谓词。

下面,我们将从0 的延续开始,(cont(0)) 然后仅当当前延续的值小于3 时才添加1——随后对when (lt (3)) (f) 的调用将返回一个延续不变的价值

// cont :: a -> cont a
const cont = x =>
  k => k (x)
  
// when :: (a -> Bool) -> (a -> cont a) -> a -> cont a
const when = p => f => x =>
  p (x) ? f (x) : cont (x)

// contAdd :: Number -> Number -> cont Number
const contAdd = x => y =>
  cont (x + y)
  
// lt :: Number -> Number -> Bool
const lt = x => y =>
  y < x
  
// contLog :: a -> a
const contLog = x =>
  (console.log(x), cont(x))
  
// demo
cont (0)
  (contLog) // => 0
  (when (lt (3)) (contAdd (1)))
  (contLog) // => 1
  (when (lt (3)) (contAdd (1)))
  (contLog) // => 2
  (when (lt (3)) (contAdd (1)))
  (contLog) // => 3
  (when (lt (3)) (contAdd (1)))
  (contLog) // => 3
  (when (lt (3)) (contAdd (1)))
  (contLog) // => 3
  

【讨论】:

  • 谢谢!有没有办法保持呼叫的顺序 - 先 A,然后 B?在这里当然很容易看到相反的性质,但在实际代码中可能会导致惊喜。
【解决方案3】:

一个想法是使用这样的承诺设置一个队列来链接异步计算:

function compute(queue, previousResult) {
    if (!queue.length) return previousResult;
    return new Promise((resolve, reject) => {
        //Get Operation
        var operation = queue.shift();
        //If there is nothing to calculate just resolve the promise
        if (!operation[0]) {
            resolve(0);
        }
        //Execute the computation function and give it the 
        //resolve callback to resolve the promise when the calculations done
        operation[1](operation[0], previousResult || null, resolve);
    }).then(result => {
        //Call the next calculation with result of the previous one
        return compute(queue, result);
    });
}

然后:

var A = 10;

function computeA(a, previous, resolve) {
    $.get('https://httpbin.org/get').then(function() {
        resolve(a*10);
    });
}

var B = 20;

function computeB(b, previous, resolve) {
    resolve(previous + b * 10);
}

var C = 20;

function computeC(c, previous, resolve) {
    resolve(previous + c * 10);
}


compute([
    [A, computeA],
    [B, computeB],
    [C, computeC]
]).then(function(result) {
    console.log(result);
});

演示:

function compute(queue, previousResult) {
    if (!queue.length) return previousResult;
    return new Promise((resolve, reject) => {
        //Get Operation
        var operation = queue.shift();
        //If there is nothing to calculate just resolve the promise
        if (!operation[0]) {
            resolve(0);
        }
        //Execute the computation function
        operation[1](operation[0], previousResult || null, resolve);
    }).then(result => {
        //Call the next calculation with result of the previous one
        return compute(queue, result);
    });
}

var A = 10;

function computeA(a, previous, resolve) {
    $.get('https://httpbin.org/get').then(function() {
        resolve(a*10);
    });
}

var B = 20;

function computeB(b, previous, resolve) {
    resolve(previous + b * 10);
}

var C = 20;

function computeC(c, previous, resolve) {
    resolve(previous + c * 10);
}


compute([
    [A, computeA],
    [B, computeB],
    [C, computeC]
]).then(function(result) {
    console.log(result);
});
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-04
    • 2015-03-28
    • 1970-01-01
    • 2014-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-17
    相关资源
    最近更新 更多