我正在尝试弄清楚 Promise 是如何工作的,我已经理解了一个基本概念,但我真的不明白我应该如何等待多个 Promise 完成。特别是因为它们是动态创建的,一个接一个。
如果有人能为我指明更优雅的解决方案,我会很高兴。
简而言之,我需要的是:
*我在我的应用程序中使用 localforage,但我正在使用 setTimeout 模拟它。
我想过使用这种方法进行序列迭代: JavaScript ES6 promise for loop
for (let i = 0, p = Promise.resolve(); i < 10; i++) {
p = p.then(_ => new Promise(resolve =>
setTimeout(function () {
console.log(i);
resolve();
}, Math.random() * 1000)
));
}
这很棘手,因为我没有在此迭代完成时创建所有承诺,所以我需要单独跟踪它们(承诺)并且只在它们出现时运行“Promise.allSettled”。
这是我的测试小提琴 https://jsfiddle.net/mefistofelos/2ergotvw/
此处为完整代码:
let app = {
"data": {
"arr" : [5,10,15,20,25,30,35,"1.oni"],
"ids" : [1,2/*,3,4,5,6,7,8,9,10*/,100],
"items" : [{"id": 1, "name": "apple"},{"id": 2, "name": "pear"},{"id": 3, "name": "plum"},{"id": 4, "name": "ananas"},{"id": 17, "name": "brick"}],
getItem : (id, ptIndex) => new Promise(
resolve => setTimeout(
() => {
let resp = {"id": id, "data": [], "ptIndex" : ptIndex};
resp.data = app.data.items.filter( (ob) => ob.id == id );
console.log("id: " + id + " ptIndex: " + ptIndex, resp);
resolve(resp)
}
, Math.floor((Math.random() * 1500) + 300))
),
setItem : (data) => new Promise(
(resolve) => setTimeout(
() => {
let resp = data;
resp.status = "success";
app.promisesSequence._items.push(data);
console.log("setItem Resp Data", data);
return resolve(resp);
}
, Math.floor((Math.random() * 2500) + 800))
)
},
// build a set of anonymous functions and run them in sequence
"promisesSequence": {
// holds promise functions
"_items" : [],
/*"_track" : [],*/
"_promiseArr" : [],
// initiate promise tracking
"track" : {
"multiplier" : 2,
"data" : [],
start : (total) => {
app.promisesSequence.track.data.push({"total": total,"arr":[]});
return app.promisesSequence.track.data.length-1;
},
// add promise to the promise tracking tree
addPromise : (ptIndex, promise) => {
app.promisesSequence.track.data[ptIndex].arr.push(promise);
return promise;
},
isReady : (ptIndex) => (app.promisesSequence.track.getTotal(ptIndex) == app.promisesSequence.track.getTracked(ptIndex) ),
getTotal : (ptIndex) => app.promisesSequence.track.data[ptIndex].total*app.promisesSequence.track.multiplier,
getTracked : (ptIndex) => app.promisesSequence.track.data[ptIndex].arr.length,
getPromises : (ptIndex) => app.promisesSequence.track.data[ptIndex].arr,
},
onFinishCb: _ => {
console.log("[onFinishCb]: Script finished, ("+app.promisesSequence._items.length+") items added: ", app.promisesSequence._items);
},
// build promise function array
build: _ => {
console.log("init promisesSequence");
// start tracking items
let ptIndex = app.promisesSequence.track.start(app.data.ids.length);
console.log("ptIndex: " + ptIndex);
// go through array
for (let i = 0, p = Promise.resolve(); i <= app.data.ids.length-1; i++) {
console.log("get Item " +app.data.ids[i]+" Data: " );
p = p.then( _ => {
app.promisesSequence.track.addPromise(ptIndex,app.data.getItem(app.data.ids[i], ptIndex)).then(
(resp) => {
console.log("GOT item (" + resp.id + ") data: ", resp.data);
if ( resp.data.length >= 1 ) {
item = resp.data[resp.data.length-1];
item.edited = true;
item.a = "edit";
} else {
item = {"id": resp.id, "data": [], "name" : "", "a" : "insert"};
}
// pass promiseTreeIndex
item.ptIndex = resp.ptIndex;
console.log("Try to Set item ("+item.id+"): ",item);
app.promisesSequence.track.addPromise(item.ptIndex, app.data.setItem(item)).then (
(resp) => console.log("Item ("+resp.id+") is Set.", resp)
)
// try to bind CB after the last of the GET requests have been created
if ( app.promisesSequence.track.isReady(item.ptIndex) === true ) {
console.log("**Tracked Promises: " + app.promisesSequence.track.getTracked(item.ptIndex) + " From Total of " + app.promisesSequence.track.getTotal(item.ptIndex));
console.log("Call Promise.allSettled");
Promise.allSettled(app.promisesSequence.track.getPromises(item.ptIndex)).then(app.promisesSequence.onFinishCb);
}
return i;
})
})
}
console.log("iteration complete");
},
run: () => {
return app.promisesSequence.build();
}
}
}
app.promisesSequence.run();
如您所见,它是按顺序添加项目,并且我在“GET”和“SET”函数中都有正确的数据,所以我已经弄清楚了。
我的问题: 有没有比我想出的更专业的方法呢? 我希望避免跟踪我创建的每一个承诺。通过更进一步,我可以手动检查它们是否已完成,这样我什至不需要使用 .allSettled 方法。
答案 0 :(得分:0)
await/async 可能正是我想要的。 这样它就更短了,而且几乎与我昨天在问题中写的一样。
但是......第一轮检查不是异步的......它们不是并行检查......我想我需要更多地考虑这个......
let app = {
"data": {
"ids" : [1,2,3,4,5,6,7,8,9,10,100],
"items" : [{"id": 1, "name": "apple"},{"id": 2, "name": "pear"},{"id": 3, "name": "plum"},{"id": 4, "name": "ananas"},{"id": 17, "name": "brick"}],
getItem : (id) => new Promise(
resolve => setTimeout(
() => {
let resp = {"id": id, "data": []};
resp.data = app.data.items.filter( (ob) => ob.id == id );
//console.log("id: " + id , resp);
resolve(resp)
}
, Math.floor((Math.random() * 1500) + 300))
),
setItem : (data) => new Promise(
(resolve) => setTimeout(
() => {
let resp = data;
resp.status = "success";
app.promisesSequence._items.push(data);
//console.log("setItem Resp Data", data);
return resolve(resp);
}
, Math.floor((Math.random() * 2500) + 800))
)
},
// build a set of anonymous functions and run them in sequence
"promisesSequence": {
// holds promise functions
"_items" : [],
onFinishCb: _ => {
console.log("Script finished, ("+app.promisesSequence._items.length+") items added: ", app.promisesSequence._items);
},
// build promise function array
build: async _ => {
console.log("init promisesSequence");
// go through array
for (let i = 0; i <= app.data.ids.length-1; i++) {
console.log("get Item: " +app.data.ids[i] );
var result = await app.data.getItem(app.data.ids[i]);
console.log( "["+app.data.ids[i]+"] WE HAVE THE ITEM");
if ( result.data.length == 1 ) {
item = result.data[result.data.length-1];
item.a = "edit";
} else {
item = {"id": result.id, "data": [], "a" : "insert"};
}
console.log("Set item: "+item.id);
var result = await app.data.setItem(item);
console.log( "["+app.data.ids[i]+"] ITEM DATA AFTER INSERT: ", result);
}
console.log("iteration complete, trigger onFinishCb now");
app.promisesSequence.onFinishCb();
},
run: () => {
return app.promisesSequence.build();
}
}
}
app.promisesSequence.run();