我想实现这样的一个异步函数:以 async 方式询问一些用户输入,然后执行一个耗时的异步操作,再将这个异步操作以 Promise 形式返回。调用数次这个异步函数,将返回的 Promise 放进一个数组,并等待它们全部执行完成。
如果没有看懂我的描述,可以看看具体代码,大概长这样: https://gist.github.com/t123yh/9ace77dc3acc3809562bbd7574503694
使用 Node.js 7.10.0 运行。
这份代码中,有两个地方标记了 Style 1 和 Style 2。仅有 Style 2 能够正常工作; Style 1 无法实现预期目标。
这是一个 feature 吗?如果是,能够找到文档说明吗?我好像没找到。
1
seki 2017-05-31 23:34:29 +08:00
|
2
seki 2017-05-31 23:38:59 +08:00
你这个例子不能直接浏览器运行,所以只能说我的感觉,你第一种写法应该算是直接 resolve 了这个返回的 promise
|
3
zzuieliyaoli 2017-05-31 23:51:16 +08:00
```js
const questionAsync = () => new Promise((resolve) => { setTimeout(() => { console.log('promptText') resolve(); }, 100) }); const processTask = async () => { const content = await questionAsync(); const myJob = new Promise((resolve, reject) => { setTimeout(() => { console.log('content') resolve(); }, 100); }); // Style 1 return myJob; // Style 2 // return { job: myJob }; }; (async function () { const tasks = [ { n: "UpLeft", t: 1926 }, { n: "DownLeft", t: 0817 }, { n: "UpRight", t: 1500 }, { n: "DownRight", t: 586 } ]; let v = []; for (let task of tasks) { const taskPromise = await processTask(task); // Style 1 v.push(taskPromise); // Style 2 // v.push(taskPromise.job); } await Promise.all(v); console.log("All done."); })() ``` 讲道理,楼主应该把你的逻辑抽象出来。 我这边按照我简化的代码运行,style1、styl2 都是可以的。 |
5
t123yh OP @zzuieliyaoli 我是想要这样的效果:用户在 回答了 promptText 过后,立即弹出下一个 prompt,同时 setTimrout 在后台运行,不阻塞 prompt 的过程。在我电脑( Nodejs 7.10.0 )上,Style 1 会导致下一个 prompt 在上一个 prompt 执行完之后才弹出。
|
6
zzuieliyaoli 2017-06-01 00:02:35 +08:00
不要用 setTimeout 后台轮训了,不优雅。
改写一下 Promise,主动触发 resolve,类似于 jQuery 的 Deffered 对象。 http://liubin.org/promises-book/#deferred-and-promise |
7
2zH 2017-06-01 02:47:29 +08:00 via Android
for await of?
https://github.com/tc39/proposal-async-iteration |
8
SoloCompany 2017-06-01 02:49:00 +08:00 1
你还明白吗?根本不需要!
只要没有 await, async function 都是立刻返回一个 promise 的 node -p 'async function x() { return 1; }; x()' Promise { 1 } |
9
SoloCompany 2017-06-01 02:52:57 +08:00 1
而如果使用了 await 关键字,promise 是会被无限展开的
这个语法糖过于甜美,以至于你永远不可能从 await 手里得到一个 promise object ! |
10
t123yh OP @SoloCompany 我是想要让一个函数 部分地 异步执行,我当然知道没有 await 的时候它返回 Promise,我现在想让它 await 过后返回 Promise。按你说的,这样是不行的。请问在什么地方可以找到关于这个的文档呢? MDN 里貌似没有。
|
11
t123yh OP @zzuieliyaoli 这个 setTimeout 仅作为模拟任务处理来使用,实际代码中是执行一个下载的操作。
|
12
funnyecho 2017-06-01 08:38:10 +08:00
async 的 return 应该跟 Promise.resolve() 是一个道理吧,所以你 style 1 返回的 promise 也被展开了。
|
13
codehz 2017-06-01 09:52:54 +08:00 via Android 1
你可以使用类似惰性求值的策略,返回一个零参数函数,该函数返回值为 promise,然后第一次 await 之后再(),就可以优雅的解决问题了
|
14
acthtml 2017-06-01 09:57:03 +08:00
可以,函数本身就返回 promise
async function run(){return 1} run().then(...).catch(...) |
15
SoloCompany 2017-06-01 13:00:12 +08:00 via iPhone 1
@t123yh 之前的回复已经告诉过你了不可能,因为 es 的语法糖实现定义,await 会对 promise 无限展开,永远不可能返回 promise,你只能把 promise 包一层来避免展开
|
16
SoloCompany 2017-06-01 13:23:45 +08:00 via iPhone
@t123yh 这里有一吨的语法糖
可以看一下 https://stackoverflow.com/questions/41128311/async-await-in-a-class-method-called-then await 的参数其实并不是 promise 而是 thenable 的 duck type,await 本身就是 generator is 的语法糖,yield 语句会无限调用 then 函数展开结果 |
17
iamdhj 2017-06-01 14:27:46 +08:00
把两个异步操作分开处理就好了,那样逻辑还清晰一点
|
18
joesonw 2017-06-01 17:49:39 +08:00
```
const futures = tasks.map(processTask(task)); await Promise.all(futures); ``` |
19
joesonw 2017-06-01 17:50:34 +08:00
Reply 18
joesonw 几秒前 ``` const futures = tasks.map(processTask); await Promise.all(futures); ``` |
20
Icemic 2017-06-02 14:22:31 +08:00
这都是什么啊,async 函数本来不就返回 Promise 么?
|