[英]Promise.all always returns an empty array
I'm trying to solve this promise puzzle and I've had 2 questions: 我正在努力解决这个承诺之谜,我有两个问题:
A) I'm wondering why it's returning empty array. A)我想知道它为什么返回空阵列。 What am i doing wrong?
我究竟做错了什么?
B) How can I implement async reduce? B)如何实现异步reduce?
B) How can I make it return a Async Array instead of empty array? B)如何让它返回异步数组而不是空数组?
Note: 注意:
Please make use of
.get
method to iterate through the elements and the return value must be a asyncArray (not a regular array)请使用
.get
方法迭代元素,返回值必须是asyncArray(不是常规数组)
Code looks like this: 代码如下所示:
/** * Async array. */ function AsyncArray(arr) { this._arr = arr; this.length = arr.length; } /** * Asynchronously get the array item of the * given index. * @param {number} index - array index of the desired item * @param {function} callback - called with the array item */ AsyncArray.prototype.get = function get(index, callback) { setTimeout(callback, 0, this._arr[index]); }; /** * Async version of Array.prototype.map. * @param {AsyncArray} arr * @param {function} fn - (item: any) => any * @returns {Promise<AsyncArray>} */ function asyncMap(arr, fn) { let counter = 0; // counter const res = []; /// array of promises. const len = arr.length; // Get the length. return new Promise((resolve, reject) => { // Pending. while(true) { if(counter===len) { console.log("before break", res); break; } arr.get(counter, item => { res[counter] = function() { return new Promise((resolve, reject) => { return resolve(fn(item)); }); }(); console.log('r',res); }); counter += 1; } Promise.all(res).then((r1, rej) => { console.log("hello world", r1); return resolve(res); }); }); } /** * Async version of Array.prototype.reduce. * @param {AsyncArray} arr * @param {function} fn - (val: any, item: any) => any * @returns {Promise<any>} */ function asyncReduce(arr, fn, initVal) {} const arr = new AsyncArray([1, 2, 3]); // arr.get(1, item => console.log(item)); // Existing // Expected result: [2, 4, 6]; asyncMap(arr, x => x * 2).then(arr_ => console.log('asyncMap:', arr_)); // Expected result: 106 // asyncReduce(arr, (v, x) => v + x, 100).then(val => console.log('asyncReduce:', val));
You're putting the result of the get
calls into the results array asynchronously - res
is empty when you call Promise.all
on it: 您将
get
调用的结果异步放入结果数组中 - 当您在其上调用Promise.all
时res
为空:
arr.get(counter, item => {
res[counter] = function() {
return new Promise((resolve, reject) => {
return resolve(fn(item));
});
}();
});
// at this point, nothing has been pushed to res
Promise.all(res)
called synchronously after that point won't wait for anything, because none of the items in the array are Promises. 在该点之后同步调用将不会等待任何事情,因为数组中的所有项都不是Promises。
You could push a Promise to the array synchronously instead: 您可以将Promise 同步推送到数组:
res.push(new Promise((resolve) => {
arr.get(counter, item => resolve(fn(item)));
}));
/** * Async array. */ function AsyncArray(arr) { this._arr = arr; this.length = arr.length; } /** * Asynchronously get the array item of the * given index. * @param {number} index - array index of the desired item * @param {function} callback - called with the array item */ AsyncArray.prototype.get = function get(index, callback) { setTimeout(callback, 0, this._arr[index]); }; /** * Async version of Array.prototype.map. * @param {AsyncArray} arr * @param {function} fn - (item: any) => any * @returns {Promise<AsyncArray>} */ function asyncMap(arr, fn) { let counter = 0; // counter const res = []; /// array of promises. const len = arr.length; // Get the length. return new Promise((resolve, reject) => { // Pending. while(true) { if(counter===len) { console.log("before break", res); break; } res.push(new Promise((resolve) => { arr.get(counter, item => resolve(fn(item))); })); counter += 1; } Promise.all(res).then((r1, rej) => { console.log("hello world", r1); return resolve(r1); }); }); } /** * Async version of Array.prototype.reduce. * @param {AsyncArray} arr * @param {function} fn - (val: any, item: any) => any * @returns {Promise<any>} */ function asyncReduce(arr, fn, initVal) {} const arr = new AsyncArray([1, 2, 3]); // arr.get(1, item => console.log(item)); // Existing // Expected result: [2, 4, 6]; asyncMap(arr, x => x * 2).then(arr_ => console.log('asyncMap:', arr_)); // Expected result: 106 // asyncReduce(arr, (v, x) => v + x, 100).then(val => console.log('asyncReduce:', val));
I'd prefer to use .map
on an array of the internal array's length to map each arr.get
call to a Promise in an array, and call Promise.all
on that array: 我更喜欢在内部数组长度的数组上使用
.map
将每个arr.get
调用映射到数组中的Promise,并在该数组上调用Promise.all
:
function AsyncArray(arr) { this._arr = arr; this.length = arr.length; } AsyncArray.prototype.get = function get(index, callback) { setTimeout(callback, 0, this._arr[index]); }; function asyncMap(asyncArr, fn) { return Promise.all( new Array(asyncArr.length).fill().map( (item, i) => new Promise(resolve => asyncArr.get(i, item => resolve(fn(item)))) ) ).then((result) => { console.log("hello world", result); return result; }); } const arr = new AsyncArray([1, 2, 3]); asyncMap(arr, x => x * 2).then(arr_ => console.log('asyncMap:', arr_));
For async reduce, have the accumulator be a Promise that resolves to the array after having been pushed in the last iteration: 对于异步reduce,让累加器成为Promise,在最后一次迭代中推送后解析为数组:
function asyncReduce(asyncArr, fn, initVal) { return new Array(asyncArr.length).fill().reduce( (a, _, i) => a.then(resultsArr => { // feel free to use asynchronous operations here return new Promise((resolve) => { asyncArr.get(i, resultItem => { resultsArr.push(fn(resultItem)); resolve(resultsArr); }); }); }), Promise.resolve(initVal) ); } function AsyncArray(arr) { this._arr = arr; this.length = arr.length; } AsyncArray.prototype.get = function get(index, callback) { setTimeout(callback, 0, this._arr[index]); }; const arr = new AsyncArray([1, 2, 3]); asyncReduce(arr, x => x * 2, []).then(arr_ => console.log('asyncReduce:', arr_));
To also return instances of asyncArray
, just call new AsyncArray
before resolving, for example: 要返回
asyncArray
实例,只需在解析之前调用new AsyncArray
,例如:
function asyncReduce(asyncArr, fn, initVal) { return new Array(asyncArr.length).fill().reduce( (a, _, i) => a.then(resultsArr => { // feel free to use asynchronous operations here return new Promise((resolve) => { asyncArr.get(i, resultItem => { resultsArr.push(fn(resultItem)); resolve(resultsArr); }); }); }), Promise.resolve(initVal) ) .then((resultArr) => new AsyncArray(resultArr)); } function AsyncArray(arr) { this._arr = arr; this.length = arr.length; } AsyncArray.prototype.get = function get(index, callback) { setTimeout(callback, 0, this._arr[index]); }; const arr = new AsyncArray([1, 2, 3]); asyncReduce(arr, x => x * 2, []).then(arr_ => console.log('asyncReduce:', arr_));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.