Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第 24 题:实现 Promise.all #30

Open
lgwebdream opened this issue Jun 19, 2020 · 13 comments
Open

第 24 题:实现 Promise.all #30

lgwebdream opened this issue Jun 19, 2020 · 13 comments
Labels
JavaScript teach_tag 头条 company 微医 company 有赞 company 滴滴 company 编程题 teach_tag

Comments

@lgwebdream
Copy link
Owner

Promise.all = function (arr) {
  // 实现代码
};
@lgwebdream
Copy link
Owner Author

lgwebdream commented Jun 19, 2020

1) 核心思路

  • ①接收一个 Promise 实例的数组或具有 Iterator 接口的对象作为参数
  • ②这个方法返回一个新的 promise 对象,
  • ③遍历传入的参数,用Promise.resolve()将参数"包一层",使其变成一个promise对象
  • ④参数所有回调成功才是成功,返回值数组与参数顺序一致
  • ⑤参数数组其中一个失败,则触发失败状态,第一个触发失败的 Promise 错误信息作为 Promise.all 的错误信息。

2)实现代码
一般来说,Promise.all 用来处理多个并发请求,也是为了页面数据构造的方便,将一个页面所用到的在不同接口的数据一起请求过来,不过,如果其中一个接口失败了,多个请求也就失败了,页面可能啥也出不来,这就看当前页面的耦合程度了~

function promiseAll(promises) {
  return new Promise(function(resolve, reject) {
    if(!Array.isArray(promises)){
        throw new TypeError(`argument must be a array`)
    }
    var resolvedCounter = 0;
    var promiseNum = promises.length;
    var resolvedResult = [];
    for (let i = 0; i < promiseNum; i++) {
      Promise.resolve(promises[i]).then(value=>{
        resolvedCounter++;
        resolvedResult[i] = value;
        if (resolvedCounter == promiseNum) {
            return resolve(resolvedResult)
          }
      },error=>{
        return reject(error)
      })
    }
  })
}

// test
let p1 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(1)
    }, 1000)
})
let p2 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(2)
    }, 2000)
})
let p3 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(3)
    }, 3000)
})
promiseAll([p3, p1, p2]).then(res => {
    console.log(res) // [3, 1, 2]
})

@lgwebdream lgwebdream added JavaScript teach_tag 头条 company 微医 company 有赞 company 滴滴 company 编程题 teach_tag labels Jun 19, 2020
@sjw0608
Copy link

sjw0608 commented Jul 10, 2020

  /**
   * Promise.all
   * @description 当这个数组里的所有promise对象全部变为resolve状态的时候,才会resolve, 当有一个promise对象变为reject状态时,就不再执行直接 reject
   * @param {*} values promise对象组成的数组作为参数
   */

Promise.prototype.all = (values)=>{
  return new Promise((resolve,reject)=>{
      let resultArr = []
      let count = 0
      let resultByKey = (value,index)=>{
           resultArr[index] = value
           if(++count === values.length){
                resolve(resultArr)
           }
      }
      values.forEach((promise,index)=>{
         promise.then((value)=>{
            resultByKey(value,index)
         },reject)
      })
  })

}

@Genzhen Genzhen closed this as completed Jul 20, 2020
@GolderBrother
Copy link

GolderBrother commented Jul 21, 2020

Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(promises)) {
            throw new Error('argument must be a array');
        }
        // 用来记录Promise成功的次数
        let resolveCount = 0,
            // 用来保存Promise成功的结果
            resolveDataList = [];
        for (let index = 0, len = promises.length; index < len; index++) {
            const p = promises[index];
            Promise.resolve(p).then(data => {
                resolveDataList[index] = data;
                // promise成功次数等于promises数组长度,则成功
                if (++resolveCount === len) {
                    resolve(resolveDataList);
                }
                // 有一个失败就失败
            }, reject);
        }
    });
}

Promise.race = (promises = []) => {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(promises)) {
            throw new TypeError(`argument must be a array`);
        }
        for (const p of promises) {
            // 有一个成功就返回成功状态的promise
            // 有一个失败就返回失败状态的promise
            p.then(resolve, reject);
        }
    });
}


// Promise.finally() 最终的,无论如何finally中传递的回调函数 必须会执行,如果返回一个promise,会等待这个Promise执行完成
Promise.prototype.finally = function(callback){
    return this.then(res => {
        // 如果then方法返回一个Promise, 就会等待这个方法执行完毕,所以需要包装成Promise才能等待
        return Promise.resolve(callback()).then(() => res);
    }, err => {
        return Promise.resolve(callback()).then(() => {
            throw err;
        })
    });
}

let p1 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(1)
    }, 1000)
})
let p2 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(2)
    }, 2000)
})
let p3 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(3)
    }, 3000)
})
Promise.all([p3, p1, p2]).then(res => {
    console.log(res) // [3, 1, 2]
});

@Genzhen Genzhen reopened this Jul 29, 2020
@songshuangfei
Copy link

Promise.myAll = function (arr) {
  const length = arr.length;
  let result = new Array(length);
  let count = 0;
  let succeedCount = 0;

  let resolveAllFn = null;
  let rejectAllFn = null;

  let someErr = null;

  function addcount() {
    count++;
    if (count === length) {
      succeedCount === length
        ? resolveAllFn(result)
        : rejectAllFn(someErr)
    }
  }

  for (const [i, p] of arr.entries()) {
    Promise.resolve(p).then((res) => {
      result[i] = res;
      succeedCount++;
      addcount();
    }, (err) => {
      someErr = err;
      addcount();
    })
  }

  return new Promise((rs, rj) => {
    resolveAllFn = rs;
    rejectAllFn = rj;
  })
}

Promise.myAll([
  new Promise(rs=>{
    setTimeout(() => {
      rs(0)
    }, 1000);
  }),
  Promise.resolve(1),
]).then((res) => {
  console.log(res);//[ 0, 1]
});

Promise.myAll([
  new Promise((_, rj)=>{
    setTimeout(() => {
      rj(0)
    }, 1000);
  }),
  Promise.resolve(1),
]).then(() => {},err=>{
  console.log(err); //0
});

@keshidong
Copy link

Promise.all = (...promises) => {
  const results = [];

  const merged = promises.reduce(
    (acc, p) => acc.then(() => p).then(r => results.push(r)),
    Promise.resolve(null));

  return merged.then(() => results);
};

from: https://eddmann.com/posts/implementing-promise-all-and-promise-race-in-javascript/

@Fnll
Copy link

Fnll commented Apr 11, 2021

Promise.all = async (promises) => {
  const results = [];
  for (promise of promises) {
    results.push(await promise);
  }

  return results;
};

@Luoyuda
Copy link

Luoyuda commented Jun 10, 2021

function all(promiseList) {
    return new Promise((resolve, reject) => {
        if(!promiseList || !promiseList.length) return resolve([])
        let count = 0
        let length = promiseList.length
        let result = []
        for (let i = 0; i < length; i++) {
            Promise.resolve(promiseList[i]).then(value => {
                result[count++] = value
                if(count === length) resolve(result)
            }, reason => {
                reject(reason)
            })
        }
    })
}
function race(promiseList) {
    return new Promise((resolve, reject) => {
        if(!promiseList || !promiseList.length) return resolve()
        let length = promiseList.length
        for (let i = 0; i < length; i++) {
            Promise.resolve(promiseList[i]).then(value => {
                resolve(value)
            }, reason => {
                reject(reason)
            })
        }
    })
}
function allSettled(promiseList) {
    return new Promise((resolve, reject) => {
        if(!promiseList || !promiseList.length) return resolve([])
        let count = 0
        let length = promiseList.length
        let result = []
        for (let i = 0; i < length; i++) {
            Promise.resolve(promiseList[i]).then(value => {
                result[count++] = {
                    value,
                    status: 'fulfilled'
                }
                if(count === length) resolve(result)
            }, reason => {
                result[count++] = {
                    reason,
                    status: 'rejected'
                }
                if(count === length) resolve(result)
            })
        }
    })
}
var promiseList = new Array(3).fill(0).map((item, index) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(index)
        }, index * 1000)
    })
})
Promise.all(promiseList).then(list => {
    console.log(list)
})
all(promiseList).then(list => {
    console.log(list)
})
Promise.race(promiseList).then(list => {
    console.log(list)
})
race(promiseList).then(value => {
    console.log(value)
})
Promise.allSettled(promiseList).then(list => {
    console.log(list)
})
allSettled(promiseList).then(list => {
    console.log(list)
})

@Luoyuda
Copy link

Luoyuda commented Jun 10, 2021

function all(promiseList) {
        return new Promise((resolve, reject) => {
            if(!promiseList || !promiseList.length) return resolve([])
            let count = 0
            let length = promiseList.length
            let result = []
            for (let i = 0; i < length; i++) {
                Promise.resolve(promiseList[i]).then(value => {
                    result[count++] = value
                    if(count === length) resolve(result)
                }, reason => {
                    reject(reason)
                })
            }
        })
    }
    function race(promiseList) {
        return new Promise((resolve, reject) => {
            if(!promiseList || !promiseList.length) return resolve()
            let length = promiseList.length
            for (let i = 0; i < length; i++) {
                Promise.resolve(promiseList[i]).then(value => {
                    resolve(value)
                }, reason => {
                    reject(reason)
                })
            }
        })
    }
    function allSettled(promiseList) {
        return new Promise((resolve, reject) => {
            if(!promiseList || !promiseList.length) return resolve([])
            let count = 0
            let length = promiseList.length
            let result = []
            for (let i = 0; i < length; i++) {
                Promise.resolve(promiseList[i]).then(value => {
                    result[count++] = {
                        value,
                        status: 'fulfilled'
                    }
                    if(count === length) resolve(result)
                }, reason => {
                    result[count++] = {
                        reason,
                        status: 'rejected'
                    }
                    if(count === length) resolve(result)
                })
            }
        })
    }
    var promiseList = new Array(3).fill(0).map((item, index) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(index)
            }, index * 1000)
        })
    })
    Promise.all(promiseList).then(list => {
        console.log(list)
    })
    all(promiseList).then(list => {
        console.log(list)
    })
    Promise.race(promiseList).then(list => {
        console.log(list)
    })
    race(promiseList).then(value => {
        console.log(value)
    })
    Promise.allSettled(promiseList).then(list => {
        console.log(list)
    })
    allSettled(promiseList).then(list => {
        console.log(list)
    })

@zizxzy
Copy link

zizxzy commented Nov 5, 2021

const promiseAll = (promises) => {
  const newPromise = new Promise(function (resolve, reject) {
    if (!Array.isArray(promises)) reject(new Error('promises is not array'));

    const promiseLength = promises.length;
    let promiseResolveCount = 0;
    let promiseResolveResult = [];
    for (let promise in promises) {
      Promise.resolve(promise).then(value => {
        promiseResolveResult.push(value);
        promiseResolveCount++;
        if (promiseResolveCount === promiseLength) resolve(promiseResolveResult);
      }, error => {
        reject(error);
      })
    }
  });
  return newPromise;
}

// test
let p1 = new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve(1)
  }, 1000)
})
let p2 = new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve(2)
  }, 2000)
})
let p3 = new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve(3)
  }, 3000)
})
promiseAll([p3, p1, p2]).then(res => {
  console.log(res) // [3, 1, 2]
})

@SnailOwO
Copy link

SnailOwO commented Nov 11, 2021

 async function promiseAll(ary = []) {
        if (typeof ary[Symbol.iterator] !== 'function') {
            throw new Error('尚未拥有Iterator接口')
        }
        const returnAry = []
        try {
            for (const val of ary) {
                returnAry.push(await val)
            }
            return returnAry
        } catch (err) {
            console.log('all error:', err)
            return err
        }
    }

 let p1 = new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve(1)
        }, 1000)
    })

    let p2 = new Promise(function(resolve, reject) {
        setTimeout(function() {
            // resolve(2)
            reject('demo error test')
        }, 2000)
    })

    let p3 = new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve(3)
        }, 3000)
    })

    promiseAll([p3, p1, p2]).then(res => {
        console.log(res) // [3, 1, 2]
    })

@52mti
Copy link

52mti commented Mar 21, 2022

Promise.all = promises => {
const executor = (resolve, reject) => {
const responses = [];
const success = res => {
responses.push(res);
if (responses.length === promises.length) resolve(responses);
};

promises.forEach(promise => promise.then(success, reject));

};
return new Promise(executor);
};

@chinbor
Copy link

chinbor commented Aug 2, 2023

Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    let len = promises.length
    const result = []

    promises.forEach((promise, i) => {
      Promise.resolve(promise).then((res) => {
        len--
        result[i] = res

        if (len === 0) resolve(result)
      }).catch(err => {
        reject(err)
      })
    })
  })
}

const promise1 = new Promise((resolve) => {
  setTimeout(() => {
    resolve(1)
  }, 2000)
})

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(2)
  }, 100)
})

Promise.all([promise1, promise2]).then(res => {
  console.log(res)
}).catch(err => {
  console.error(err)
})

@Kisthanny
Copy link

Kisthanny commented Mar 21, 2024

/**
 * Promise.all
 * 接收一个promise列表
 * 返回一个新的Promise对象
 * 当所有promise都resolved时,按入参顺序resolve出value列表
 * 如果有promise rejected,立刻reject该error
 */

上次手写的MyPromise

class MyPromise {
  constructor(executor) {
    this.status = "pending";
    this.value = undefined;
    this.error = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (data) => {
      if (this.status === "pending") {
        this.status = "fulfilled";
        this.value = data;
        this.onFulfilledCallbacks.forEach((cb) => cb(this.value));
      }
    };
    const reject = (error) => {
      if (this.status === "pending") {
        this.status = "rejected";
        this.error = error;
        this.onRejectedCallbacks.forEach((cb) => cb(this.error));
      }
    };
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      if (this.status === "fulfilled") {
        try {
          const result = onFulfilled(this.value);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      } else if (this.status === "rejected") {
        try {
          const result = onRejected(this.error);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      } else {
        this.onFulfilledCallbacks.push((value) => {
          try {
            const result = onFulfilled(value);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });
        this.onRejectedCallbacks.push((error) => {
          try {
            const result = onRejected(error);
            resolve(result);
          } catch (err) {
            reject(err);
          }
        });
      }
    });
  }
}

all方法

MyPromise.all = function (promiseList) {
  return new MyPromise((resolve, reject) => {
    const valueList = promiseList.map(() => undefined);
    let successCount = 0;
    promiseList.forEach((p, index) => {
      p.then(
        (res) => {
          valueList[index] = res;
          successCount++;
          if (successCount.length === promiseList.length) {
            resolve(valueList);
          }
        },
        (err) => {
          reject(err);
        }
      );
    });
  });
};

测试

const p1 = new MyPromise((res, rej) => {
  setTimeout(() => {
    res(1);
  }, 5000);
});

const p2 = new MyPromise((res, rej) => {
  setTimeout(() => {
    res(2);
  }, 6000);
});

const p3 = new MyPromise((res, rej) => {
  setTimeout(() => {
    rej(new Error(3));
  }, 1500);
});

MyPromise.all([p1, p2, p3]).then(
  (res) => console.log(res),
  (err) => console.error(err)
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
JavaScript teach_tag 头条 company 微医 company 有赞 company 滴滴 company 编程题 teach_tag
Projects
None yet
Development

No branches or pull requests