我想按顺序处理一些 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));
值得注意的是,createH1
和appendChild
是同步函数。这种方法有效地允许您将普通功能链接在一起,并模糊同步和异步之间的界限。它的执行/行为也与您最初发布的代码完全一样。
是的,最后一个代码示例可能更有趣一些。
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/