javascript - 将无限循环中的等待转换为原始 promise.then

标签 javascript promise ecmascript-2017

据我所知,async/await 只是 promise.then 的语法糖。考虑这个代码片段:

function sleep(n){
    return new Promise(res => setTimeout(res, n));
}

function* range(n){
    var i = 0;
    while(i < n)    yield i++;
}
async function doStuff(){
    for(let n of range(10)){
        console.log(n);          // print the number
        await sleep(1000);       // wait for 1 second
    }
}

async/await 使代码非常线性、高效且易于理解。要记住的一件事是 range 不必有一个实际的结束就可以工作。

现在的问题是如何使用 ES7 之前时代的 promise.then 重写它。下面是同一循环的可能实现:

function doStuff(){
    return Array.from(range(10)).reduce((acc, ele) => {
        return acc
            .then(() => console.log(ele))
            .then(() => sleep(1000))
    }, Promise.resolve());
}

忽略代码不是很优雅的事实,使用 Array.from(range(10))

  1. 创建一个不需要的额外数组,并且
  2. 假设 range(10) 将在未来的某个时间点结束。

看起来不是很好的转换。

我们也可以通过将 yield 用作 await 来完全重新发明轮子,但这会使语法不符合 ES5。这里的目标是:

  1. 使用符合 ES5 的语法重写
  2. 使用 promise 返回 sleep 函数
  3. 动态链接 sleep promise ,同时允许迭代器没有结束
  4. doStuff 可以链接:

    doStuff().finally(cleanUp);  // clean up if something failed
    
  5. (可选)代码不应过于复杂

有什么想法吗?

最佳答案

我认为以下内容可能会起作用,您的示例没有说明如何处理解析值以及它与迭代器值的关系,因此我更改了 sleep 的调用方式。

一些 promise polyfils 可能会用完具有高 promise 链的堆栈空间,所以你应该检查你的 polyfil(如果它的实现返回并继续使用 setTimeout,堆栈应该清除,但一些 polyfils 可能不会以这种方式实现)。

    function sleep(n){
      return new Promise(res => setTimeout(_=>res(n/100), n));
    }

    function* range(n){
      var i = 0;
      while(i < n)    yield i++;
    }

    function doStuff(){
      const processValue = 
        resolve => {
          console.log("resolved with:",resolve);
          // if(resolve===3){throw "nope";}
          return sleep(resolve*100);
        },
      rec = (p,iter) => {
        const result = iter.next();
        if (result.done){
          return p;
        }
        p = p.then(_=>processValue(result.value))
        return p.then(
          resolve=>{
            return rec(p,iter)
          }
        );
      },
      iter = range(10),
      firstResult = iter.next();
      if(firstResult.done){
        return processValue(firstResult.value);
      }
      return rec(processValue(firstResult.value),iter);
    }

    doStuff()
    .then(
      x=>console.log("done:",x)
      ,reject=>console.warn("fail:",reject)
    );

关于javascript - 将无限循环中的等待转换为原始 promise.then,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47624573/

相关文章:

javascript - 将动态 Html 内容写入页面或弹出窗口

javascript - 每列的总和不基于 jQuery 中的类

javascript - 通过Firebug分析DOM事件:hover

javascript - Python API 不返回 JSON 对象

javascript - 如何将 Mongoose promise 循环限制为只有几次?

javascript - 使用 Ajax Promise/Deferred

javascript - 在 React.js 中将 Async/Await 与 Axios 一起使用

angular - 观察者函数中的异步等待

node.js - 带有异步等待的 Node repl

javascript - 在react-native组件中实现async/await函数