Mar*_*eby 6 javascript promise ecmascript-6
我想在序列中处理许多承诺.我在下面有一段工作代码,但我想知道我是否过度复杂了承诺的链接.我似乎正在创造大量新的封闭装置,我想知道我是否遗漏了一些东西.
有没有更好的方法来编写此函数:
'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;
}
Run Code Online (Sandbox Code Playgroud)
@TheToolBox有一个很好的答案.
只是为了好玩,我将向您展示一种替代技术,它使用从协同程序中获取灵感的生成器.
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();
}
Run Code Online (Sandbox Code Playgroud)
使用它,您的代码将如下所示
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');
}());
Run Code Online (Sandbox Code Playgroud)
使用承诺生成器可以做一些非常有趣的事情.它们在这里并不是很明显,因为你的addElement承诺并没有解决任何实际价值.
如果你真的resolve有些价值观,你可以做点什么
// 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));
Run Code Online (Sandbox Code Playgroud)
值得注意,createH1并且appendChild是同步功能.这种方法有效地允许您将正常功能链接在一起,并模糊同步和异步之间的界限.它的执行/行为与您最初发布的代码完全相同.
所以,是的,最后一个代码示例可能会更有趣.
最后,
协程相对于
.then链接的一个明显优势是所有已解析的promise都可以在同一范围内访问.
比较.then链......
op1()
.then(x => op2(x))
.then(y => op3(y)) // cannot read x here
.then(z => lastOp(z)) // cannot read x or y here
Run Code Online (Sandbox Code Playgroud)
对于协程......
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 !
}
Run Code Online (Sandbox Code Playgroud)
当然有使用承诺的解决方法,但哦,男孩,它变得难看快...
如果您对以这种方式使用发电机感兴趣,我强烈建议您检查合作项目.
无论如何,我希望你学习其他一些技巧^ __ ^
您的代码看起来接近您可以在此处获得的最佳代码。承诺可能是一种奇怪的结构,需要习惯,尤其是编写承诺化代码通常最终会将一个函数嵌入另一个函数中。正如您在这里所看到的,这是一个非常常用的措辞。只能做出两个风格上的改变。首先,myPromise这是不必要的,只会添加令人困惑的额外代码行。直接返回promise就更简单了。其次,您可以在一开始就使用函数绑定来简化您的调用。它可能不在函数本身内部,但它确实消除了几个闭包。两项更改如下所示:
'use strict';
addElement("first")
.then(addElement.bind(null,"second"))
.then(addElement.bind(null,"third"))
.then(addElement.bind(null,"fourth"))
function addElement(elementText){
return 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);
});
}
Run Code Online (Sandbox Code Playgroud)
值得指出的是,如果你愿意稍微重组一下,就会形成一个稍微更有吸引力的设计:
'use strict';
var myWait = waitRand.bind(null,2000);
myWait
.then(addElement.bind(null, "first"))
.then(myWait)
.then(addElement.bind(null, "second"))
.then(myWait)
.then(addElement.bind(null, "third"))
function waitRand(millis) {
return new Promise((resolve, reject) => {
setTimeout(resolve, Math.random() * millis);
}
}
function addElement(elementText) {
var element = document.createElement('h1');
element.innerText = `${elementText} ${Date.now()}`;
document.body.appendChild(element);
}
Run Code Online (Sandbox Code Playgroud)
为了清晰起见,这会牺牲承诺链的长度,并且嵌套级别也会稍微少一些。