Javascript 纯函数能否返回一个在随机时间段后解析的承诺?

Javascript 纯函数能否返回一个在随机时间段后解析的承诺?,javascript,functional-programming,Javascript,Functional Programming,我知道这个例子很做作,但我仍然好奇这是否可以被视为一个纯函数: const addAsync = (x, y) => new Promise((resolve, reject) => { setTimeout( () => resolve(x + y), Math.random() * 1000 ); }); 对该函数的每次调用都返回一个承诺,该承诺解析为两个参数之和。承诺在0到1秒之间的随机时间后解析 出于所有目的,这似乎是完

我知道这个例子很做作,但我仍然好奇这是否可以被视为一个纯函数:

const addAsync = (x, y) => new Promise((resolve, reject) => {
    setTimeout(
        () => resolve(x + y),
        Math.random() * 1000
    );
});
对该函数的每次调用都返回一个承诺,该承诺解析为两个参数之和。承诺在0到1秒之间的随机时间后解析


出于所有目的,这似乎是完全纯粹的,这意味着我可以在测试或代码中将此函数视为纯粹的函数
(a,b)->Promise(a+b)
。但是,由于我们使用的是
Math.random()
,因此无法将此函数转换为查找表并返回,而不会丢失功能(我们会丢失延迟)。所以这可以被认为是纯粹的吗?

< P>我相信它可以被认为是一个纯粹的函数。纯函数定义为返回值仅由其输入值确定,且无明显副作用的函数

在这种情况下,输出仅由输入决定,不会产生任何副作用。计算结果所需的时间不同,这一事实不应影响其纯度

但我要警告的是,我不是函数式编程专家,我可能错了

我想说的是,我们不知道返回的承诺所处的状态,就像。承诺要么已经解决,要么被拒绝,要么悬而未决,但我们无法预测它何时处于何种状态。概述以下内容的片段:

 let a = 0;
 addAsync(1,2).then(res => a += res).then(console.log);
 addAsync(0, 1).then(res => a += res).then(console.log);

如果addAsync是纯的,那么它的日志总是一样的。

让我们先澄清一下纯这个术语。纯度意味着引用透明性,也就是说,在不改变程序行为的情况下,可以用计算结果替换表达式。这是一个返回承诺的操作。要将我执行的日志记录视为副作用,请执行以下操作:

constaddasync=(x,y)=>newpromise((r,e)=>{
设置超时(
z=>(console.log(z),r(z)),
Math.random()*1000,
x+y
);
});
控制台日志(“之前”);
addAsync(2,3);
控制台日志(“之后”);
//日志
“以前”
“之后”

5
简单的答案是否定的。但我提供了一种简单的方法将杂质推到别处

在代码的纯部分

const incRandomDelay = addAsync.bind(null,1)
incRandomDelay(10).then( sum => writeToFile(sum) )
现在,在代码的效果部分的某个地方

const incRandomDelay = addAsync.bind(null,1)
incRandomDelay(10).then( sum => writeToFile(sum) )

如何通过参数提供持续时间,而不是在函数中计算它。当然,它将失去随机性,但函数将变得纯粹。我认为随机性或持续时间不应该是函数关注的问题。@isa424我当然同意,这不是好代码,我不打算实际使用这个函数。这个例子是故意设计来提出这样一个问题的:像随机延迟的解析这样的东西是否可以被认为是纯的。有趣的例子。然而,我认为这里的问题不在于
addAsync
不纯净,而在于
res=>a+=res
不纯净并导致副作用。@basilikum hmmm。我部分同意这一点,因为它也适用于
。然后(()=>console.log(“first”)
。我们没有得到比的全局状态,但输出仍然会不同。那么可以安全地说,所有异步函数都是不纯净的,因为我们无法保证执行顺序吗?@basilikum IMO是的。但实际上我讨厌这种意义上的定义。每个意义都有irs范围,可以说纯函数是为函数和同步语言定义的,这些原则不能在这里应用。这很公平。我想一个更普遍的问题是,纯度是否也取决于“如何”和“何时”返回某物,或者仅仅取决于“返回什么”。但在大多数实际例子中,返回异步承诺很可能意味着执行某种IO,因此自动拥有一个不纯净的函数。所以,也许这是一个毫无意义的例子,正如你所说,它只存在于函数式编程的范围之外。我不同意你的替换。用值
5
替换
addAsync(2,3)
。但是,
addAsync(2,3)
不会返回
5
它会返回一个承诺,因此您不应该将其替换为:
(新承诺((r)=>r(5))。然后(console.log)
?…但它保证会延迟解析。因此,在返回承诺时,承诺将始终处于挂起状态。@basilikum是的,你是对的,但你还需要评估chained
然后
方法。在这种情况下,我实际上不太确定如何表示已解析的承诺。我认为
新承诺((res,rej)=>res(console.log(5))
最接近。@JonasW.Javascript
Promise
构造函数被急切地执行。您指的是延迟的
Promise
解析过程,它发生在当前事件循环迭代的末尾。@t据我所知,目标是替换
addAsync(2,3)
使用静态值,用查找表替换函数。
addAsync(2,3)
返回解析为
5
的承诺。这意味着可以用
新承诺(r=>r(5))替换它
。因此,如果你只是做这个替换,那么你的两个示例实际上会以完全相同的顺序记录行。但是我同意有一种情况,执行顺序不再得到保证,例如,如果你涉及另一个异步函数。
Math.random()
是一个迭代器。
addAsync()
有步进迭代器的副作用。@PatrickRoberts,而
Math.random()
增加了副作用,我认为这不是可观察到的副作用。