Javascript ES6承诺和PEP3148期货的连锁差异

Javascript ES6承诺和PEP3148期货的连锁差异,javascript,python,async-await,promise,future,Javascript,Python,Async Await,Promise,Future,我对ES6承诺和PEP3148期货执行差异的原因有些困惑。在Javascript中,当承诺被另一个承诺解析时,“外部”承诺在解析或拒绝后继承“内部”承诺的值。在Python中,“外部”未来会立即用“内部”未来本身来解决,而不是用它的最终值来解决,这就是问题所在 为了说明这一点,我为这两种平台提供了两个代码片段。在Python中,代码如下所示: import asyncio async def foo(): return asyncio.sleep(delay=2, result=42)

我对ES6承诺和PEP3148期货执行差异的原因有些困惑。在Javascript中,当承诺被另一个承诺解析时,“外部”承诺在解析或拒绝后继承“内部”承诺的值。在Python中,“外部”未来会立即用“内部”未来本身来解决,而不是用它的最终值来解决,这就是问题所在

为了说明这一点,我为这两种平台提供了两个代码片段。在Python中,代码如下所示:

import asyncio

async def foo():
    return asyncio.sleep(delay=2, result=42)

async def bar():
    return foo()

async def main():
    print(await bar())

asyncio.get_event_loop().run_until_complete(main())
async def unwind(value):
    while hasattr(value, '__await__'):
        value = await value

    return value
在Javascript中,完全等效的代码如下:

function sleep(delay, result) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(result);
        }, delay * 1000);
    });
}

async function foo() {
    return sleep(2, 42);
}

async function bar() {
    return foo();
}

(async function main() {
    console.log(await bar());
})();
sleep
为完整性而提供的功能

Javascript代码按预期打印
42
。Python代码打印出
,并且从未等待过关于“coroutine'foo'的投诉”

通过这种方式,JS允许您通过立即
wait
等待承诺,或让调用方等待承诺,来选择控件将从当前执行上下文中消失的时间点。Python实际上只给您留下了总是等待未来/协同程序的选项,因为否则您将不得不自己使用一个丑陋的包装函数来解开循环中的未来链,如下所示:

import asyncio

async def foo():
    return asyncio.sleep(delay=2, result=42)

async def bar():
    return foo()

async def main():
    print(await bar())

asyncio.get_event_loop().run_until_complete(main())
async def unwind(value):
    while hasattr(value, '__await__'):
        value = await value

    return value

那么,问题是:这个决定背后有什么理由吗?为什么Python不允许连锁期货?有没有讨论过?有什么方法可以使行为与承诺更接近吗?

让我快速比较一下JavaScript的承诺和Python的未来,在这里我可以指出主要用例并揭示 决定背后的原因

我将使用以下虚拟示例演示异步函数的使用:

异步函数concatNamesById(id1,id2){ 返回(等待getNameById(id1))+','+(等待getNameById(id2)); } 异步JavaScript 在承诺的概念出现之前,人们使用回调编写代码。关于这个问题仍然有各种各样的惯例 哪个参数应该是回调,错误应该如何处理,等等。。。最后,我们的函数如下所示:

import asyncio

async def foo():
    return asyncio.sleep(delay=2, result=42)

async def bar():
    return foo()

async def main():
    print(await bar())

asyncio.get_event_loop().run_until_complete(main())
async def unwind(value):
    while hasattr(value, '__await__'):
        value = await value

    return value
//使用回调
函数concatNamesById(id1、id2、回调){
getNameById(id1,函数(err,name1){
如果(错误){
回调(err);
}否则{
getNameById(id2,函数(err,name2){
如果(错误){
回调(err);
}否则{
回调(null,name1+','+name2);
}
});
}
});
}
这与示例相同,是的,我故意使用了4个缩进空格来放大所谓的回调地狱或 . 多年来,使用JavaScript的人一直在编写这样的代码

然后,通过引入承诺的概念,拯救了失望的JavaScript社区。 这个名字故意不是“未来”或“任务”。承诺概念的主要目标是摆脱金字塔。为了实现这一承诺 拥有一种方法,该方法不仅允许您订阅在获得承诺值时触发的事件,而且还将 返回另一个承诺,允许链接。这就是承诺和未来的不同概念。承诺要多一些

//使用链接承诺
函数concatNamesById(id1,id2){
变量名称1;
返回getNameById(id1)。然后返回函数(temp){
名称1=温度;
return getNameById(id2);//这里我们从'then'返回一个承诺
})//然后返回一个新的承诺,解析为“getNameById(id2)”,允许链接
.then(函数(名称2){
返回name1+','+name2;//这里我们从中返回一个立即值
});//最后一个也会返回一个承诺,这个承诺最终会被返回
}
看到了吗?打开
返回的承诺,然后打开
回调,以构建一个干净、透明的链,这是非常重要的。(我自己编写了这种异步操作系统
代码超过一年。)
然而,当您需要一些控制流(如条件分支或循环)时,事情会变得复杂。
当ES6的第一个编译器/Transpiler(如6to5)出现时,人们慢慢开始使用生成器。ES6发电机是双向的,这意味着
生成器不仅生成值,而且可以在每次迭代中接收提供的值。这使我们能够编写以下代码:

//使用生成器和承诺
const concatNamesById=Q.async(函数*(id1,id2){
返回值(yield-getNameById(id1))+','+(yield-getNameById(id2));
});
仍然使用promises,从生成器生成异步函数。这里没有黑魔法,这个包装器函数是使用 只有承诺。然后(或多或少)。我们快到了

如今,由于ES7已经相当成熟,任何人都可以使用它将异步ES7代码编译成ES5

//使用真正的异步等待
异步函数concatNamesById(id1,id2){
返回(等待getNameById(id1))+','+(等待getNameById(id2));
}
从异步函数返回承诺 所以这是可行的:

async foo(){
返回/*等待*/睡眠('bar',1000);
//不需要等待!
}
这也是:

async foo(){
返回等待'酒吧';
//你可以在任何你想要的地方写等待!
}
这种弱/动态/duck类型非常适合JavaScript的世界观

您是对的,您可以从异步函数返回一个承诺,而无需等待,而且它是无意识的。 这不是一个真正的决定,而是
承诺的直接结果。然后
工作,因为它解开了
承诺让锁链更舒适。尽管如此,我认为在每一天之前写下等待是一个很好的习惯
async call以明确您知道调用是异步的。我们确实有多个bug
每天都因为缺少等待关键字,因为他们会