YvetteLau / Step-By-Step

不积跬步,无以至千里;
704 stars 66 forks source link

实现 Promise.all 方法 #25

Open YvetteLau opened 5 years ago

mdchun commented 5 years ago
// ...
static all(list) {
 let len = list.length
 let res = new Array(len)
 let count = 0;
 return new Promise((resolve,reject)=> {
     list.forEach((p, index) => {
        Promise.resolve(p).then(d => {
           res[index] = d
           count++

           if(count === len) {
             resolve(res)
           }
        }, err => {
            reject(err)
        })
     })
  })
}
luohong123 commented 5 years ago

Promise.all 接收一个 promise 对象的数组作为参数,当这个数组里的所有 promise 对象全部变为resolve或 有 reject 状态出现的时候,它才会去调用 .then 方法,它们是并发执行的。

  1. 如果元素不是 Promise 对象,则使用 Promise.resolve 转成 Promise 对象

  2. 如果全部成功,状态变为 resolved,返回值将组成一个数组传给回调

  3. 只要有一个失败,状态就变为 rejected,返回值将直接传递给回调 all() 的返回值也是新的 Promise 对象

Yuko7245 commented 5 years ago

function promiseAll(promises) {
    return new Promise((resolve, reject) => {
      let resultCount = 0;
      let results = new Array(promises.length);
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(value => {
          resultCount++;
          results[i] = value;
          if (resultCount === promises.length) {
            return resolve(results)
          }
        }, error => {
          reject(error)
        })
      }
    })
}
shenanheng commented 5 years ago
 /**
   *实现promise中的all方法
   */
  function all(array) {
    judgeType(array);
    return new Promise((resolve, reject) => {
      let count = 0;
      array.forEach(element => {
        element.then(() => {
          count += 1;
          if (array.length === count) {
            resolve();
          }
        });
        element.catch((error) => {
          reject(error);
        });
      });
    });
  }
  /**
   *类型的判断
   */
  function judgeType(array) {
    if (array instanceof Array) {
      array.forEach(item => {
        if (!(item instanceof Promise)) {
          throw "该参数的每一项必须是Promise的实例";
        }
      });
    } else {
      throw "必须是数组哦";
    }
  }
taoyaoyaoa commented 5 years ago

promise 是对异步编程的一种抽象。它是一个代理对象,代表一个必须进行异步处理的函数返回的值或抛出的异常。

function promiseAll(promises) { return new Promise(function(resolve, reject) { if (!isArray(promises)) { return reject(new TypeError('arguments must be an array')); } var resolvedCounter = 0; var promiseNum = promises.length; var resolvedValues = new Array(promiseNum); for (var i = 0; i < promiseNum; i++) { (function(i) { Promise.resolve(promises[i]).then(function(value) { resolvedCounter++ resolvedValues[i] = value if (resolvedCounter == promiseNum) { return resolve(resolvedValues) } }, function(reason) { return reject(reason) }) })(i) } }) }

AILINGANGEL commented 5 years ago

Promise.all方法有以下几个特点

Promise.all = function(promises) {
    return new Promise(function(resolve, reject) {
        if (!promises || typeof promises !== 'object' || typeof promises[Symbol.iterator] !== 'function') {
            reject(TypeError());
        }
        if (promises.length === 0) {
            resolve([]);
        } else {
            let ans = [];
            let index = 0;
            for (let i = 0; i < promises.length; i++) {
                Promise.resolve(promises[i]).then(function(data) {
                    // 不能用Push操作,因为不能确定谁先回来,要用index来记录,否则无法准确获得当前收到的结果的数目
                    index++;
                    ans[i] = data;
                    if (index === promises.length) {
                        resolve(ans);
                    }
                }, function(error) {
                    reject(error);
                });
            }
        }
    });
}
into-piece commented 5 years ago
Promise.myAll = function(promises) {
  let results = [];
  let count = 0;
  let len = promises.length;
  return new Promise(function(resolve, reject) {
    if (!(promises instanceof Array))
      return reject("arguments must be an array");
    for (let val of promises) {
      Promise.resolve(val).then(
        function(res) {
          count++;
          results.push(res);
          if (count === len) {
            return resolve(results);
          }
        },
        function(err) {
          return reject(err);
        }
      );
    }
  });
};
lydfree commented 5 years ago

Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例

  const obj1= Promise.all([p1,p2])

接受一个数组参数 obj1 的状态有两种: 1.当 p1,p2 的状态都是 fulfilled 时,obj1 的状态是 fulfilled 2.p1 , p2只要其中一个的状态是 rejected,obj1 的状态是 rejected

代码:

   const p1 = new Promise((resolve,reject)=>{
        resolve()
    }).then(()=>{
        console.log('success1')
    }).catch(()=>{
        console.log('error1')
    })
   const p2 = new Promise((resolve,reject)=>{
        reject()
    }).then(()=>{
        console.log('success2')
    }).catch(()=>{
        console.log('error2')
    })
   const a = Promise.all([
       p1,
       p2
   ]).then(()=>{
       console.log('success')
   }).catch(()=>{
       console.log('error')
   })

执行结果 success1 error2 success

为什么p2是rejected状态,但是promise.all的状态却是fulfilled,输出success?因为p2抛出的错误已经在p2里面处理了,倘若p2的错误没有被处理,那么promise.all就会执行catch( )方法。

参考链接:https://es6.ruanyifeng.com/#docs/promise#Promise-all

riluocanyang commented 5 years ago

Promise.all实现

Promise.all接收一个数组,如果传入数组的每个元素不是promise对象,则将其转换为promise对象。当数组中每个promise的执行结果都变为resolve时,调用then方法的成功回调函数;如果数组中有一个promise对象的执行结果变为reject,则调用then方法的失败回调函数。

具体实现

Promise.all = (promises) => {
    return new Promise(resolve, reject){
         if(!isArray(promises)) {
                return  reject('arguments must be an array.')
         }
        let len = promises.length;
        let count = 0;
        let res = [];
        for (let i = 0; i< len; i++){
            Promise.resolve(promises[i]).then((value) => {
                count ++;
                res[i] = value;
                if (count === len) {
                    return resolve(res)
                }
            }, (reason) => {
                return reject(reason)
            })
        }
    }
}
yelin1994 commented 5 years ago

Promise.all 的实现

思量了半天,原生的Promise 无法一时写出来

这边稍微利用下Promise来实现 Promise.all

 Promise.all = arr => {
     const results = []
     return new Promise(resolve => {
        let i =0;
        function next () {
            arr[i] && arr[i].then(res=>{
                result.push(res);
                i++;
                if (i == arr.length) {
                    resolve(result)
                } esle {
                    next()
                }
            })
        }

     })
 }
xdandsl commented 5 years ago

Promise.all([p1,p2,p3]) 以数组的形式传入每个promise实例,返回一个新的promise对象 每个实例的结果均为resolve时,将结果推入数组中,并resolve出来。 有一个实例的结果为reject时,就reject出来 Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

Promise.all = promises => {
    return new Promise((resolve,reject) => {
        if(typeof promises[Symbol.iterator] != 'function' ){
            reject('类型错误')
        }
        if(promises.length == 0){
            reject([])
        }else{
            const targetArr = []
            const len = promises.length
            const index = 0
            for(let i = 0;i<len;i++){
                //通过Promise.resolve方法得到每个promise实例的结果
                Promise.resolve(promises[i]).then(value => {
                    index++;
                    targetArr[i] = value
                    if(index == len){
                        resolve(targetArr)
                    }
                }).catch(err => {
                    reject(err)
                })
            }
        }
    })
}
YvetteLau commented 5 years ago

在实现 Promise.all 方法之前,我们首先要知道 Promise.all 的功能和特点,因为在清楚了 Promise.all 功能和特点的情况下,我们才能进一步去写实现。

Promise.all 功能

Promise.all(iterable) 返回一个新的 Promise 实例。此实例在 iterable 参数内所有的 promise 都 fulfilled 或者参数中不包含 promise 时,状态变成 fulfilled;如果参数中 promise 有一个失败rejected,此实例回调失败,失败原因的是第一个失败 promise 的返回结果。

let p = Promise.all([p1, p2, p3]);

p的状态由 p1,p2,p3决定,分成以下;两种情况:

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

Promise.all 的特点

Promise.all 的返回值是一个 promise 实例

Promise.all 返回的 promise 的状态

Promise.all 实现

仅考虑传入的参数是数组的情况

/** 仅考虑 promises 传入的是数组的情况时 */
Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        if (promises.length === 0) {
            resolve([]);
        } else {
            let result = [];
            let index = 0;
            for (let i = 0;  i < promises.length; i++ ) {
                //考虑到 i 可能是 thenable 对象也可能是普通值
                Promise.resolve(promises[i]).then(data => {
                    result[i] = data;
                    if (++index === promises.length) {
                        //所有的 promises 状态都是 fulfilled,promise.all返回的实例才变成 fulfilled 态
                        resolve(result);
                    }
                }, err => {
                    reject(err);
                    return;
                });
            }
        }
    });
}

可使用 MDN 上的代码进行测试

考虑传入的参数是 一个可迭代对象

Promise.all = function (promises) {
    /** promises 是一个可迭代对象,省略对参数类型的判断 */
    return new Promise((resolve, reject) => {
        if (promises.length === 0) {
            //如果传入的参数是空的可迭代对象
            return resolve([]);
        } else {
            let result = [];
            let index = 0;
            let iterator = promises[Symbol.iterator]();
            function next() {
                try {
                    var { value, done } = iterator.next();
                    if(!done) {
                        Promise.resolve(value).then(data => {
                            result[index] = data;
                            index++;
                            next();
                        }, err => {
                            //某个promise失败
                            reject(err);
                            return;
                        });
                    }else {
                        //迭代完成
                        resolve(result);
                    }
                } catch (e) {
                    return reject(e);
                }
            }
            next(); //执行一次next
        }
    });
}

测试代码:

let p2 = Promise.all({
    a: 1,
    [Symbol.iterator]() {
        let index = 0;
        return {
            next() {
                index++;
                if (index == 1) {
                    return {
                        value: new Promise((resolve, reject) => {
                            setTimeout(resolve, 100, 'foo');
                        }), done: false
                    }
                } else if (index == 2) {
                    return {
                        value: new Promise((resolve, reject) => {
                            resolve(222);
                        }), done: false
                    }
                } else if(index === 3) {
                    return {
                        value: 3, done: false
                    }
                }else {
                    return { done: true }
                }

            }
        }

    }
});
setTimeout(() => {
    console.log(p2)
}, 200);
Cain-kz commented 5 years ago

学习promise.all(),要先了解promise的作用和特性。promise是一个对象,Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值。 promise.all() promise.all(iterable)方法返回一个promise实例,此实例在iterable参数内所有的promise都完成(resolved)或参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。(iterable:一个可迭代对象,如 Array 或 String)

var promise1 = Promise.resolve(3)
var promise2 = 42;
var promise3 = new Promise((resolve,reject)=>{
  setTimeout(resolve,1000,'foo')
})
Promise.all([promise1,promise2,promise3]).then((values)=>{
  console.log(values)     //[3,42,'foo']
})

// 下面的例子中演示了promise,all的异步性 var resolvedPromiseArray = [Promise.resolve(33),Promise.resolve(44)]; var p = Promise.all(resolvedPromiseArray); console.log(p) setTimeout((console.log('Array',p)))

// 但是,Promise.all 当且仅当传入的可迭代对象为空时为同步:
var pt = Promise.all([])
var pt2=Promise.all([1331,'nihzo'])
setTimeout(()=>{
  console.log('[]',pt2);
})
KRISACHAN commented 5 years ago

笔芯❤

      'use strict'
      const createPromise = (method) => {
        const promise = new Promise((resolve, reject) => {
          method(resolve, reject)
        })
        return promise
      }
      const all = (...tasks) => {
        tasks = tasks.flat()
        let tasksRunCount = 0
        let tasksResList = []
        let tasksLength = tasks.length
        return createPromise((resolve, reject) => {
          for (let step = 0, len = tasksLength; step < len; ++step) {
            const task = Promise.resolve(tasks[step])
            task.then(taskRes => {
              tasksRunCount++
              tasksResList[step] = taskRes
              if (tasksRunCount === tasksLength) {
                resolve(tasksResList)
              }
            }).catch(tashRej => {
              reject(tashRej)
            })
          }
        })
      }
      const p1 = createPromise((resolve, reject) => {
        resolve("p1")
      })
      const p2 = createPromise((resolve, reject) => {
        reject("p2")
      })
      const p3 = createPromise((resolve, reject) => {
        reject("p3")
      })
      all([p1, p2, p3]).then(res => {
        console.log(res)
      }).catch(err => {
        console.log(err)
      })
jodiezhang commented 5 years ago
Promise.all = function (promises) {
  return new Promise(((resolve, reject) => {
    const result = [];
    let count = 0;
    function done(i, data) {
      result[i] = data;
      if (++count === promises.length) { resolve(result); }
    }

    for (let i = 0; i < promises.length; i++) {
      Promise.resolve(promises[i]).then((data) => {
        done(i, data);
      }, reject);
    }
  }
  ));
};

测试代码

let promise1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, '200');
  })
let promise2 = 43
let promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, '100');
});

Promise.all([promise1,promise2, promise3]).then((values) => {
  console.log(values); // [200, 43, 100]
}, (err) => {
  console.log(err)
});
chongyangwang commented 5 years ago

什么是promise.all

promise.all传入多个promise对象 返回一个新的promise实例 promise.all返回的结果有如下几种状态 示例代码:

const result = promise.all(p1,p2,p3)

成功状态 当p1 ,p2,p3 都执行完毕之后,且都返回success,那么promise.all,会返回一个数组,分别是三个promise对象的返回结果,状态为fullfilled。

失败状态 当p1,p2,p3 都执行完毕,只要其中任何一个出现错误,那么promise.all会返回一个当前的错误实例,状态为rejected。

实现一个promise.all(般一下大佬的代码):

Promise.all = function (promises) {

return new Promise((resolve, reject) => {

    if (promises.length === 0) {

        resolve([]);

    } else {

        let result = [];

        let index = 0;

        for (let i = 0;  i < promises.length; i++ ) {

            //考虑到 i 可能是 thenable 对象也可能是普通值

            Promise.resolve(promises[i]).then(data => {

                result[i] = data;

                if (++index === promises.length) {

                    //所有的 promises 状态都是 fulfilled,promise.all返回的实例才变成 fulfilled 态

                    resolve(result);

                }

            }, err => {

                reject(err);

                return;

            });

        }

    }

});

}

ZadaWu commented 5 years ago

实现Promise.all

function isArray(object){
    return object && typeof object==='object' &&
            object instanceof Array;
}

Promise.myall = function (promiseList) {
  if (!isArray(promiseList)) {
    return 'not an array'
  }
  return new Promise ((resolve, reject)=> {
    let count = 0
    promiseList.forEach(element => {
        element.then(() => {
          count ++;
          if (promiseList.length === count) {
            resolve()
          }
        }).catch(error =>{
          reject(error)
        })
    })
  })
}

测试代码

var p1 = Promise.resolve(1),
    p2 = Promise.reject(2),
    p3 = Promise.resolve(3);
Promise.myall([p1, p2, p3]).then(function (results) {
    //then方法不会被执行
    console.log(results);
}).catch(function (e){
    //catch方法将会被执行,输出结果为:2
    console.log(2);
});
Diamondjcx commented 5 years ago
function runAsync1(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务1执行完成');
            resolve('随便什么数据1');
        }, 1000);
    });
    return p;            
}
function runAsync2(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务2执行完成');
            resolve('随便什么数据2');
        }, 2000);
    });
    return p;            
}
function runAsync3(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务3执行完成');
            resolve('随便什么数据3');
        }, 2000);
    });
    return p;            
}

Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。我们仍旧使用上面定义好的runAsync1、runAsync2、runAsync3这三个函数,看下面的例子

Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
    console.log(results);
});

用Promise.all来执行,all接收一个数组参数,里面的值最终都算返回Promise对象。这样,三个异步操作的并行执行的,等到它们都执行完后才会进到then里面。那么,三个异步操作返回的数据哪里去了呢?都在then里面呢,all会把所有异步操作的结果放进一个数组中传给then,就是上面的results。

有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据,是不是很酷?有一个场景是很适合用这个的,一些游戏类的素材比较多的应用,打开网页时,预先加载需要用到的各种资源如图片、flash以及各种静态文件。所有的都加载完后,我们再进行页面的初始化。

MissNanLan commented 5 years ago
Promise.nanlan = function (promises) {
  let promiselength = promises.length;
  let result = [];
  let count =0;
  return new Promise(function (resolve, reject) {
    if (!(promises instanceof Array)) {
      return reject("params muse be Arrary");
    }
    for (let i = 0; i < promises.length; i++) {
      Promise.resolve(promises[i]).then((res) => {
        count++;
        result[i] = res;
        if ( count === promiselength) {
          return resolve(result)
        }
      },  (err) =>{
        return reject(err)
      })
    }
  })
}
// 测试代码

var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

Promise.nanlan([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});
omnip620 commented 4 years ago
Promise.all = async function (promises) {
  const res = [];
  try {
    for await (let p of promises) {
      const val = p;
      res.push(val);
    }
    return Promise.resolve(res);
  } catch (err) {
    return Promise.reject(err);
  }
};
chaos1ee commented 4 years ago
Promise.all = Promise.all || function(promises) {
  return new Promise((resolve, reject) => {
    if (!Array.isArray(promises)) {
      return reject("arguments must be array");
    }

    if (!promises.length) {
      resolve([]);
    }

    let count = 0;
    const values = [];

    for (let i = 0; i < promises.length; i++) {
      Promise.resolve(promises[i]).then(
        res => {
          count++;
          values[i] = res;
          if (count === promises.length) {
            resolve(values);
          }
        },
        err => {
          reject(err);
        }
      );
    }
  });
};
yanlee26 commented 2 years ago

无论怎么手动模拟,Promise.all 的并发这个根本 feature 难实现的。 借助 web-worker 算是一条思路。

lydfree commented 2 years ago

这是来自QQ邮箱的假期自动回复邮件。你好,你的邮件我已经收到了,辛苦你了!

lwhere commented 2 years ago

使用async / await写法改写了一下函数实现,更容易理解

function promiseAll(promises) {
  let promsieLength = promises.length;
  let resolvedLength = 0;
  let resolvedResults = [];

  return new Promise(async (resolve, reject) => {
    for(let i = 0; i < promsieLength; i++) {
      let result = await promises[i];
      resolvedLength++;
      resolvedResults.push(result);
      if(resolvedLength === promsieLength) {
        resolve(resolvedResults)
      }
    }
  })
}
// 测试用例
let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 1000)
})

let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(3)
  }, 2000)
})

let p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(2)
  }, 3000)
})

promiseAll([p1, p2, p3]).then(res => {
  console.log(res)
})
lydfree commented 2 years ago

这是来自QQ邮箱的假期自动回复邮件。你好,你的邮件我已经收到了,辛苦你了!