简体   繁体   English

Promise.all总是返回一个空数组

[英]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.allres为空:

      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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM