Javascript promise 序列

标签 javascript promise ecmascript-6

我想按顺序处理一些 promise 。我有一个 working piece of code下面,但我想知道我是否将 promise 的链接过于复杂。我似乎正在创建大量新的闭包,我挠头想知道我是否遗漏了什么。

这个函数有没有更好的写法:

'use strict';
addElement("first")
.then(x => {return addElement("second")})
.then(x => { return addElement("third")})
.then(x => { return addElement("fourth")})   

function addElement(elementText){
    var myPromise = new Promise(function(resolve,reject){
        setTimeout(function(){
            var element=document.createElement('H1');
            element.innerText = `${elementText} ${Date.now()}`;
            document.body.appendChild(element);
            resolve();
        }, Math.random() * 2000);
    });
return myPromise;
}

最佳答案

@TheToolBox 为您提供了一个很好的答案。

为了好玩,我将向您展示一种使用生成器的替代技术,其灵感来自 coroutines。 .

Promise.prototype.bind = Promise.prototype.then;

const coro = g => {
  const next = x => {
    let {done, value} = g.next(x);
    return done ? value : value.bind(next);
  }
  return next();
}

使用它,您的代码将如下所示

const addElement = elementText =>
  new Promise(resolve => {
    setTimeout(() => {
      var element = document.createElement('H1');
      element.innerText = `${elementText} ${Date.now()}`;
      document.body.appendChild(element);
      resolve();
    }, Math.random() * 2000);
  });

coro(function* () {
  yield addElement('first');
  yield addElement('second');
  yield addElement('third');
  yield addElement('fourth');
}());

使用带有 promise 的生成器可以做一些非常有趣的事情。它们在这里不是很明显,因为您的 addElement promise 不会解析任何实际值。


如果您实际上解析一些值,您可以做类似的事情

// sync
const appendChild = (x,y) => x.appendChild(y);

// sync
const createH1 = text => {
  var elem = document.createElement('h1');
  elem.innerText = `${text} ${Date.now()}`;
  return elem;
};

// async
const delay = f =>
  new Promise(resolve => {
    setTimeout(() => resolve(f()), Math.random() * 2000);
  });

// create generator; this time it has a name and accepts an argument
// mix and match sync/async as needed
function* renderHeadings(target) {
  appendChild(target, yield delay(() => createH1('first')));
  appendChild(target, yield delay(() => createH1('second')));
  appendChild(target, yield delay(() => createH1('third')));
  appendChild(target, yield delay(() => createH1('fourth')));
}

// run the generator; set target to document.body
coro(renderHeadings(document.body));

值得注意的是,createH1appendChild 是同步函数。这种方法有效地允许您将普通功能链接在一起,并模糊同步和异步之间的界限。它的执行/行为也与您最初发布的代码完全一样。

是的,最后一个代码示例可能更有趣一些。


Lastly,

One distinct advantage the coroutine has over the .then chaining, is that all of the resolved promises can be accessed inside the same scope.

比较 .then 链 ...

op1()
  .then(x => op2(x))
  .then(y => op3(y))    // cannot read x here
  .then(z => lastOp(z)) // cannot read x or y here

到协程...

function* () {
  let x = yield op1(); // can read x
  let y = yield op2(); // can read x and y here
  let z = yield op3(); // can read x, y, and z here
  lastOp([x,y,z]);     // use all 3 values !
}

当然还有workarounds为此使用 promises,但是天哪,它会很快变得丑陋吗...


如果您有兴趣以这种方式使用生成器,我强烈建议您查看 co项目。

这是一篇文章,Callbacks vs Coroutines ,来自 co 的创建者,@tj .

无论如何,我希望你在学习一些其他技术时玩得开心^__^

关于Javascript promise 序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35777797/

相关文章:

javascript - 如何获取jquery变量children?

javascript - Firefox WebExtensions,通过路径获取本地文件内容

javascript - 在 HTML5 中显示嵌套的不等长 JSON 数组

javascript - 异步构建一个数组,迭代其他数组

reactjs - React PropTypes.oneOf 指定枚举不起作用

javascript - 使用固定边栏(EDGE 和 Firefox)时的 HTML5 Masonry 边距/间距问题

javascript - Node.js 中的 Promise Bluebird 出现问题

javascript - 在递归 promise 中返回的 then() 是什么意思

javascript - redux 中异步操作后的 setState

JavaScript:在模板变量内添加 if 条件