KieSun / all-of-frontend

你想知道的前端内容都在这

Home Page:https://yuchengkai.cn/docs/frontend

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

第十八题:请实现 Promise.all

KieSun opened this issue · comments

commented

请实现 Promise.all

去答题

新建了一个大厂真题每日打卡群,有意愿学习打卡的再进,请备注打卡

Promise.all = function(arr) {
  if(!Array.isArray(arr)) {
    throw new Error('参数必须是数组')
  }
  return new Promise((resolve, reject) => {
    const list = []
    arr.forEach(item => {
      this.resolve(item).then((value) => {
        list.push(value)
        if(list.length === arr.length) {
          resolve(list)
        }
      }, (err)=> {
        reject(err)
      })
    })
  })
}
Promise.All = function (arg) {
    if (!Array.isArray(arg)) {
        return Promise.reject(new Error('参数必须是数组'))
    }
    return new Promise((resolve, reject) => {
        let count = 0;
        const totalCount = arg.length
        const results = []

        arg.forEach((item, index) => {
            const ret = item?.then ? item : Promise.resolve(item)
            ret.then(result => {
                count++
                results[index] = result
                if (count === totalCount) {
                    resolve(results)
                }
            }).catch(error => {
                reject(error)
            })
        })
    })
}

const request = (data) => new Promise((resolve, reject) => {
    setTimeout(() => {
        if (Math.random() < 0.9) {
            resolve(data)
        } else {
            reject(data)
        }
    }, 2000 * Math.random());
})

Promise.All([1, 2, 3, request(4)]).then(ret => {
    console.log("ret2", ret)
}).catch(error => {
    console.error("error2", error)
})
// ret2 (4) [1, 2, 3, 4]


Promise.All(new Array(10).fill(null).map((e, i) => request(i))).then(ret => {
    console.log("ret", ret)
}).catch(error => {
    console.error("error", error)
})
// ret (10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Promise.all = function(arr) {
  if(!Array.isArray(arr)) {
    throw new Error('参数必须是数组')
  }
  return new Promise((resolve, reject) => {
    const list = []
    arr.forEach(item => {
      this.resolve(item).then((value) => {
        list.push(value)
        if(list.length === arr.length) {
          resolve(list)
        }
      }, (err)=> {
        reject(err)
      })
    })
  })
}

@learnRy 返回结果顺序不对

const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";

class MyPromise {
  constructor(callback) {
    this.status = PENDING;
    this.value = null;
    this.resolvedCB = [];
    this.rejectedCB = [];
    callback(this.resolve.bind(this), this.reject.bind(this));
  }
  resolve(data) {
    this.value = data;
    this.status = RESOLVED;
    this.resolvedCB.forEach((cb) => {
      this.value = cb(this.value);
    });
    this.resolvedCB = [];
  }
  reject(data) {
    this.value = data;
    this.status = REJECTED;
    this.rejectedCB.forEach((cb) => {
      this.value = cb(this.value);
    });
    this.rejectedCB = [];
  }
  then(handleResolved, handleRejected) {
    handleResolved && this.resolvedCB.push(handleResolved);
    handleRejected && this.rejectedCB.push(handleRejected);

    if (this.status === RESOLVED) {
      this.resolvedCB.forEach((cb) => {
        this.value = cb(this.value);
      });
      this.resolvedCB = [];
    }
    if (this.status === REJECTED) {
      this.rejectedCB.forEach((cb) => {
        this.value = cb(this.value);
      });
      this.rejectedCB = [];
    }
  }
}

MyPromise.all = function (promises) {
  const allData = [];
  return new MyPromise((resolve, reject) => {
    const run = () => {
      if (promises.length === 0) return;
      const promise = promises.shift();
      if (promise) {
        promise.then((data) => {
          allData.push(data);
          if (promises.length === 0) {
            resolve(allData);
          } else {
            run();
          }
        });
      }
    };
    run();
  });
};

// test
const a = new MyPromise((resolve) => {
  setTimeout(() => resolve("a"), 200);
});
const b = new MyPromise((resolve) => {
  setTimeout(() => resolve("b"), 800);
});
const c = new MyPromise((resolve) => {
  setTimeout(() => resolve("c"), 100);
});

MyPromise.all([a, b, c]).then((data) => console.log("allData", data));
// ["a", "b", "c"]
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";

class MyPromise {
  constructor(callback) {
    this.status = PENDING;
    this.value = null;
    this.resolvedCB = [];
    this.rejectedCB = [];
    callback(this.resolve.bind(this), this.reject.bind(this));
  }
  resolve(data) {
    this.value = data;
    this.status = RESOLVED;
    this.resolvedCB.forEach((cb) => {
      this.value = cb(this.value);
    });
    this.resolvedCB = [];
  }
  reject(data) {
    this.value = data;
    this.status = REJECTED;
    this.rejectedCB.forEach((cb) => {
      this.value = cb(this.value);
    });
    this.rejectedCB = [];
  }
  then(handleResolved, handleRejected) {
    handleResolved && this.resolvedCB.push(handleResolved);
    handleRejected && this.rejectedCB.push(handleRejected);

    if (this.status === RESOLVED) {
      this.resolvedCB.forEach((cb) => {
        this.value = cb(this.value);
      });
      this.resolvedCB = [];
    }
    if (this.status === REJECTED) {
      this.rejectedCB.forEach((cb) => {
        this.value = cb(this.value);
      });
      this.rejectedCB = [];
    }
  }
}

MyPromise.all = function (promises) {
  const allData = [];
  return new MyPromise((resolve, reject) => {
    const run = () => {
      if (promises.length === 0) return;
      const promise = promises.shift();
      if (promise) {
        promise.then((data) => {
          allData.push(data);
          if (promises.length === 0) {
            resolve(allData);
          } else {
            run();
          }
        });
      }
    };
    run();
  });
};

// test
const a = new MyPromise((resolve) => {
  setTimeout(() => resolve("a"), 200);
});
const b = new MyPromise((resolve) => {
  setTimeout(() => resolve("b"), 800);
});
const c = new MyPromise((resolve) => {
  setTimeout(() => resolve("c"), 100);
});

MyPromise.all([a, b, c]).then((data) => console.log("allData", data));
// ["a", "b", "c"]

这个MyPromise不符合Promise/A+规范

  • 1.输入是一个每一项是Promise的iterable类型数据(Array,Set,Map)
  • 2.输出是一个新的Promise实例value(2种情况 reslove一个数组 或reject第一个错误)
  • 3.要做的工作:检查是否传入的为数组,检查传入的每一项是否为Promise实例,创建一个新的Promise实例A,将输入的每一个Promise实例都执行,获取resolve的value,并组成一个数组Arr,作为新创建Promise实例A的reslove的对象,如果其中有不合法的错误或者reject,Promise实例A会立即抛出第一个错误
function _all(arr) {
    //数组类型检查
    if (!Array.isArray(arr)) {
        throw new TypeError('is not Array')
    }
    return new Promise(function (reslove, reject) {
        try {
            let result = []
            for (let item of arr) {
                 //检查实例是否为Promises实例
                if (Object.prototype.toString.call(item).indexOf("Promise") == -1) {
                    //没有的话返回当前值(为了保证按顺序执行,自己封装一个Promise实例)
                    item = new Promise(function (reslove, reject) {
                        reslove(item)
                    })
                }
                item.then((res, err) => {
                    if (err) {
                        throw new Error(err)
                    } else {
                        result.push(res)
                        if (arr.indexOf(item) == arr.length - 1) {
                            reslove(result)
                        }
                    }
                })
            }
        } catch (error) {
            reject(error)
        }
    })
}
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'foo');
});
const promise4 = function name(params) {
    
};
_all([promise2, promise1, promise4,promise3]).then(res => {
    console.log(res, 'cc');
})
//[ 42, 3, [Function: name], 'foo' ] cc
function promiseAll(list) {
    if (!Array.isArray(list)) {
        throw new Error('参数错误')
    }
    const result = []
    const n = list.length
    let successCount = 0
    list.forEach((item, index) => {
        item.then(res => {
            result[index] = res
            successCount++
            if (n === successCount) {
                return Promise.resolve(result)
            }
        }).catch(e => {
            return Promise.reject(e)
        })
    })
}
// 请实现 Promise.all

Promise.all = (arr) => {
  const length = arr.length;
  const result = [];
  let count = 0;

  return new Promise((resolve, reject) => {
    arr.forEach((item, index) => {
      if (item instanceof Promise) {
        item.then(
          (res) => {
            result[index] = res;
            count += 1;
            if (count === length) resolve(result);
          },
          (error) => {
            reject(error);
          }
        );
      } else {
        result[index] = item;
        count += 1;
        if (count === length) resolve(result);
      }
    });
  });
};

代码实现

Promise.myAll = function (promises) {
  let count = 0;
  return new Promise((resolve, reject) => {
    let result = new Array(promises.length);
    for (let i = 0; i < promises.length; i += 1) {
      const promise = promises[i];
      if (promise instanceof Promise) {
        promise
          .then((res) => {
            result[i] = res;
            count += 1;
            if (count === promises.length) {
              resolve(result);
            }
          })
          .catch((err) => {
            reject(err);
          });
      } else {
        result[i] = promise;
        count += 1;
        if (count === promises.length) {
          resolve(result);
        }
      }
    }
  });
};

测试用例

const p1 = new Promise((resolve) => {
  setTimeout(() => {
    resolve('hello');
  }, 1000);
});

const p2 = new Promise((resolve) => {
  setTimeout(() => {
    resolve('world');
  }, 500);
});

const p3 = 999;

const p4 = Promise.reject('this is an error');

Promise.myAll([p1, p2, p3]).then((res) => {
  console.log(`res: `, res);
});
// res: [ 'hello', 'world', 999 ]

Promise.myAll([p1, p2, p3, p4])
  .then((res) => {
    console.log(`res: `, res);
  })
  .catch((error) => {
    console.log(`error: `, error);
  })
 
// error: this is an error

Promise.all

思路:

  • 返回一个新的 Promise
  • 当且仅当所有异步任务完成时 resolve
  • 只要有一个异步任务异常,则直接 reject
Promise.myAll = function (array) {
  if (!Array.isArray(array)) {
    return Promise.reject(new Error("Error: The params must be an Array"));
  }
  return new Promise((resolve, reject) => {
    let count = 0;
    let result = [];
    array.forEach((element, index) => {
      const isPromise = element instanceof Promise;
      const promise = isPromise ? element : Promise.resolve(element);
      promise
        .then((res) => {
          count = count + 1;
          result[index] = res;
          if (array.length === count) {
            resolve(result);
          }
        })
        .catch((error) => reject(error));
    });
  });
};

Tips:

  • instanceof Promise 判断是否为 Promise
  • Array.isArray 判断是否为数组

刚好最近试着封装了下promise

   const ENUM = {
        PENDING: 'PENDING',
        FULFILLED: 'FULFILLED',
        REJECTED: 'REJECTED'
    }
    
    const resolvePromise = (x, promise2, resolve, reject) => {
        if (x === promise2) {
            reject(new TypeError(`Chaining cycle detected for promise #<Promise>`))
        }
        if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
            let called
            try {
                let then = x.then
                if (typeof then === 'function') {
                    then.call(x, y => {
                        if(called) return
                        called = true
                        resolvePromise(y, promise2, resolve, reject)
                     }, r => {
                        if(called) return
                        called = true
                        reject(r)
                    })
                } else {
                    resolve(x)
                }
            } catch (e) {
                if(called) return
                called = true
                reject(e)
            }
        } else {
            resolve(x)
        }
    }
    class Promise {
        constructor(executor) {
            this.status = ENUM.PENDING
            this.value = undefined
            this.reason = undefined
    
            this.onResolvedCallbacks = []
            this.onRejectedCallbacks = []
    
            const resolve = (value) => {
                if (this.status === ENUM.PENDING) {
                    this.status = ENUM.FULFILLED
                    this.value = value
                    this.onResolvedCallbacks.forEach(fn => fn())
                }
            }
    
            const reject = (reason) => {
                if (this.status === ENUM.PENDING) {
                    this.status = ENUM.REJECTED
                    this.reason = reason
                    this.onRejectedCallbacks.forEach(fn => fn())
                }
            }
    
            try {
                executor(resolve, reject)
            } catch (e) {
                reject(e)
            }
        }
        then(onFulfilled, onRejected) {
            onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v=>v
            onRejected = typeof onRejected === 'function' ? onRejected : err=>{throw err}
    
            let promise2 = new Promise((resolve, reject) => {
                if (this.status === ENUM.FULFILLED) {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value) 
                            resolvePromise(x, promise2, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                     },0)
                } else if (this.status === ENUM.REJECTED) {
                    setTimeout(() => {
                        try{
                            let x = onRejected(this.reason)
                            resolvePromise(x, promise2, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                     },0)
                } else if (this.status === ENUM.PENDING) {
                    this.onResolvedCallbacks.push(() => {
                        setTimeout(() => {
                            try {
                            let x = onFulfilled(this.value) 
                                resolvePromise(x, promise2, resolve, reject)
                            } catch (e) {
                                reject(e)
                            }
                         },0)
                    })
                    this.onRejectedCallbacks.push(() => {
                        setTimeout(() => {
                            try {
                            let x = onRejected(this.reason)
                                resolvePromise(x, promise2, resolve, reject)
                            } catch (e) {
                                reject(e)
                            }
                         },0)
                        
                    })
                }
            })
            return promise2
        }
        catch(errCallback) {
            return this.then(null, errCallback)
        }
        static resolve = (val) => {
            return new Promise((resolve, reject) => {
                resolve(val)
            })
        }
        static reject = (r) => {
            return new Promise((resolve, reject) => {
                reject(r)
            })
        }
        static all = (values) => {
            return new Promise((resolve, reject) => {
                let resultArr = []
                let orderIndex = 0
                const processResultByKey = (value, index) => {
                    resultArr[index] = value
                    if( ++orderIndex === values.length) resolve(resultArr)
                }
                for (let i = 0; i < values.length; i++) {
                    let value = values[i]
                    if (value && typeof value.then === 'function') {
                        value.then(value => {
                            processResultByKey(value, i)
                        },reject)
                    } else {
                        processResultByKey(value, i)
                    }
                }
            })
    
        }
    }
    
    Promise.prototype.defer = Promise.deferred = () => {
        let dfd = {}
        dfd.promise = new Promise((resolve, reject) => {
            dfd.resolve = resolve
            dfd.reject = reject
        })
        return dfd
    }
    
    Promise.prototype.finally = callback => {
        return this.then(value => {
            return Promise.resolve(callback().then(() => value))
        }, err => {
            return Promise.resolve(callback().then(() => {throw err}))
        })
    }
    Promise.MyAll = function(pArr) {
      const length = pArr.length
      if (!Array.isArray(pArr)) {
        throw new Error('参数必须是数组')
      }
      return new Promise((resolve, reject) => {
        let res = Array(length).fill(), count = 0
        pArr.forEach((p, idx) => {
          p = p instanceof Promise ? p : Promise.resolve(p)
          p.then((data) => {
            count++
            res[idx] = data
            if (count === length) {
              resolve(res)
            }
          }).catch(err => {
            reject(err)
          })
        })
      })
    }
    function fn(data) {
      return new Promise((resolve, reject) => {
        Math.random() < 0.7 ? resolve(data) : reject(`${data}`)
      }, Math.random() * 2000)
    }
    Promise.MyAll([0, fn(1), fn(3), 3]).then((data) => {
      console.log('data', data)
    }).catch((err) => {
      console.log('err', err)
    })

实现一个Promise.all 功能

Promise.all 是传入xxx 返回xxx

Promise.all() 方法接收一个promise的 iterable 类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组。这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的 iterable 里没有 promise 了的时候。它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。

var p1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, 'one');
});
var p2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 2000, 'two');
});
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, 'three');
});
var p4 = new Promise((resolve, reject) => {
  setTimeout(resolve, 4000, 'four');
});
var p5 = new Promise((resolve, reject) => {
  reject('reject');
});

Promise.all([p1, p2, p3, p4, p5]).then(values => {
  console.log(values);
}, reason => {
  console.log(reason)
});

//From console://"reject"

具体实现方式

// 判断该数组中的内容是否为 Promise
const isPromise = obj =>
  !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'

function promiseAll(target) {
    // 判断传入的是否为 iterable 类型的数据
    if (Array.from(target) instanceof Array) {
        // 核心逻辑 按照数组的顺序,依次执行并返回数组中
        return new Promise(async function (resolve, reject) {
            try {
                let result = []; // 保存最后返回结果的数组
                for (let i = 0; i < target.length; i++) {
                    if (isPromise(target[i])) { // 判断是否为 Promise类型
                        // 如果其中一个 Promise 出现错误了 直接就返回 不再执行后面的内容
                        const answer = await target[i];
                        result.push(answer);
                    } else {
                        result.push(target[i]); // 直接存到数组中
                    }
                }
                resolve(result);
            } catch (err) {
                reject(err);
            }
        })
    } else {
        throw new TypeError(typeof target + target + 'is not iterable (cannot read property Symbol(Symbol.iterator))'); // 返回类型错误 例如 boolean 类型不能进行枚举
    }
}

const p1 = Promise.reject(3);
const p2 = 42;
const p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

promiseAll([p1, p2, p3]).then(res => {
    console.log(res); 
}).catch(err => {
    console.log(err);
})

疑问

  1. 怎么在同步的代码里面获取到 Promise的状态?目前使用的方法是 await 但是感觉不太优雅而且容易出问题
commented
function PromiseAll(promiseArray) {
    return new Promise(function(resolve, reject) {
        if(!Array.isArray(promiseArray)){
            return reject(new TypeError("参数必须是数组"));
        }
        let resolveArray = [],
            count = 0;
        promiseArray.forEach((item, index) => {
            Promise.resolve(item).then((res) => {
                count++;
                resolveArray[index] = res;
                if(count == promiseArray.length){
                    resolve(resolveArray);
                }
            }).catch(err => {
                reject(err);
            })
        })
        
    })
}
const p1 = new Promise((resolve, reject) => {
  let num = 1;
  setTimeout(() => {
    resolve(num)
  }, 3000);
});
const p2 = 3;
const p3 = Promise.resolve(4);
const p4 = setTimeout(() => {
  console.log('sdffsd')
}, 2000);
const p5 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(5)
  }, 3000);
})
Promise.myAll = (args) =>  {
  if(!Array.isArray(args)){
    throw new Error('参数必须是数组')
  }
  return new Promise((resolve, reject) => {
    let result = [];
    for(let i = 0, len = args.length; i < len; i++) {
      Promise.resolve(args[i]).then(res => {
        result.push(res);
        if(result.length === len) {
          resolve(result)
        }
      }, (err) => {
        reject(err);
      })
    }
  });
}
const p6 = new Promise((resolve, reject) => {
  let num = 1;
  setTimeout(() => {
    if(num === 1) reject('num 不能为1')
  }, 3000);
});
Promise.myAll([p1,p2, p3, p4, p5]).then(res => {
  console.log(res, 'promise all resolve')
}, (err) => {
  console.log(err, 'promise all rejected')
});
// 执行结果
// Array(5) [3, 4, 87, 1, 5] "promise all resolve"
Promise.myAll([p2, p3, p4, p5, p6]).then(res => {
  console.log(res, 'promise all resolve')
}, (err) => {
  console.log(err, 'promise all rejected')
});
// 执行结果
// num 不能为1 promise all rejected
commented
Promise.myAll = function (arr) {
  if (!Array.isArray(arr)) {
    throw new Error("参数必须为数组");
  }
  return new Promise((resolve, reject) => {
    let result = [];
    arr.forEach((p, index) => {
      p = p.then ? p : Promise.resolve(p)
      p.then((res) => {
        result[index] = res;
        if (result.length === arr.length) {
          resolve(result);
        }
      }).catch((err) => reject(err));
    });
  });
};
const isIterable = (obj) => {
  return obj != null && typeof obj[Symbol.iterator] === "function";
};

Promise.all1 = function (arr) {
  if (!isIterable(arr)) {
    throw new TypeError(typeof arr + " " + arr + " " + "is not iterable");
  }

  return new Promise((resolve, reject) => {
    let resolvedArr = [];
    let resolvedCount = 0;
    for (let [index, value] of arr.entries()) {
      ((index, value) => {
        Promise.resolve(value).then(
          (res) => {
            resolvedCount++;
            resolvedArr[index] = res;
            if (resolvedCount === arr.length) {
              resolve(resolvedArr);
            }
          },
          (err) => {
            reject(err);
          }
        );
      })(index, value);
    }
  });
};

let p1 = Promise.resolve(3);
let p2 = 1337;
let p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "foo");
});

let p = Promise.all1([p1, p2, p3]).then((values) => {
  console.log("values", values); // [3, 1337, "foo"]
});

function myPromiseAll(params) {
if (Array.isArray(params)) {
let pros = [].concat(params);
let limitLen = pros.length;
let doneCount = 0;
let result = [];
return new Promise((resolve, reject) => {
try {
let promises = pros.map((item, index) => {
return Promise.resolve(item).then((res) => {
return res;
});
});
for (let i = 0; i < promises.length; i++) {
promises[i].then((res) => {
result.push(res);
doneCount++;
if (doneCount == promises.length) {
resolve(result);
}
});
}
} catch (error) {
reject(error);
}
});
} else {
//其他iterable处理实现
}
}

const PENDING ='PENDING';
const RESOLVED = 'RESOLVED';
const REJECTED = 'REJECTED';

class PromiseA = function(executor) {
this.status = PENDING // 初始化状态
this.value = null // 成功回调
this.reason = null // 失败的回调

// 存储订阅的内容
this.onSuccessCallbacks = []; // success callback
this.onFulfillCallbacks = []; // fulfill callback

const resolve = (value) => {
if(this.status === 'PENDING'){
this.status = RESOLVED
this.value = value
this.onSuccessCallbacks.forEach(fn => fn())
}
}

const reject = (reason) => {
if(this.status === 'PENDING') {
this.status = REJECTED
this.reason = reason
this.onFulfillCallbacks.forEach(fn => fn())
}
}

// 同步 executor调用
try {
executor(resolve, reject)
} catch ( e ) {
// 报错直接抛出
reject(e)
}

then(onFulFilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (val) => val
onRejected =
typeof onRejected === 'function'
? onRejected
: (err) => {
throw err
}
if(this.status === 'RESOLVED'){
onFulFilled(this.value)
}
if(this.status === 'REJECTED'){
onRejected(this.reason)
}

// 当Promise 里面有异步请求控制状态时,会先走到then 方法里面
// 把成功的回调和失败的回调先存储起来, 等到异步请求回来后变更状态,再触发执行
if(this.status === PENDING){
    this.onSuccessCallbacks.push(() =>{
      onFulfilled(this.value)
    });
    this.onFulfillCallbacks.push(() =>{
      onRejected(this.value)
    })
}

}
}

new PromiseA ((resolve, reject) =>{
setTimeout(() => {
resolve('中奖了~')
reject('再接再厉~')
}, 1000);
}).then((res) =>{
console.log('res', res)
}, (err) =>{
console.log('err',err)
})

只能实现一个 PromiseA , PromiseAll 暂时无法实现

Promise._all = function(promiseList = []) {
  if(!Array.isArray(promiseList)) {
    throw new TypeError('参数必须是数组')
  }
  return new Promise((resolve, reject) => {
    let count = 0;
    let res = []
    promiseList.forEach((promise, index) => {
      Promise.resolve(promise).then((value) => {
        res[index] = value
        count++
        if(count === promiseList.length) {
          resolve(res)
        }
      }, reject)
    })
  });
};
Promise._all([1, Promise.resolve(4)]).then(val => {
  console.log('ok', val) // ok [ 1, 4 ]
}).catch(err => {
  console.log('error', err)
})


Promise._all([1, Promise.resolve(4), Promise.reject(new Error('error'))]).then(val => {
  console.log('ok', val)
}).catch(err => {
  console.log('error', err) // error Error: error
})
class MyPromise {
    constructor(executor) {
        if (typeof executor != 'function') {
            throw new Error('MyPromise must accept a function as a parameter')
        }
        //promise当前的状态
        this.status = 'pending'
        //promise的值
        this.data = undefined
        //promise resolve时的回调函数集,因为在promise结束之前可能有多个回调添加到它上面
        this.onResolvedCallback = []
        //promise reject时的回调函数集,因为在promise结束之前可能有多个回调添加到它上面
        this.onRejectedCallback = []
        try {
            executor(this.resolve.bind(this), this.reject.bind(this))
            // bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值,例如,f.bind(obj),实际上可以理解为obj.f(),这时,f函数体内的this自然指向的是obj
            // https://blog.csdn.net/qlwangcong518/article/details/86261597
        } catch (err) {
            this.reject(err)
        }
    }
    resolve(value) {
        if (this.status == 'pending') {
            if (value instanceof MyPromise) {
                value.then(res => {
                    this.status = 'fulfilled'
                    this.data = res
                    this.onResolvedCallback.forEach(callback => { callback(res) })
                }, err => {
                    this.status = 'rejected'
                    this.data = err
                    this.onRejectedCallback.forEach(callback => { callback(err) })
                })
            } else {
                this.status = 'fulfilled'
                this.data = value
                this.onResolvedCallback.forEach((callback) => { callback(value) })
            }
        }
    }
    reject(reason) {
        if (this.status == 'pending') {
            this.status = 'rejected'
            this.data = reason
            this.onRejectedCallback.forEach((callback) => {
                callback(reason)
            })
        }
    }
    then(onResolved, onRejected) {
        onResolved = onResolved instanceof 'function' ? onResolved : value => value
        onRejected = onRejected instanceof 'function' ? onRejected : reason => reason
        if (this.status === 'fulfilled') {
            return new MyPromise((resolve, reject) => {
                try {
                    let result = onResolved(this.data)
                    if (result instanceof MyPromise) {
                        result.then(resolve, reject)
                    }
                    resolve(result)
                } catch (error) {
                    reject(error)
                }
            })
        }
        if (this.status === 'rejected') {
            return new MyPromise((resolve, reject) => {
                try {
                    let result = onRejected(this.data)
                    if (result instanceof MyPromise) {
                        result.then(resolve, reject)
                    }
                    resolve(result)
                } catch (e) {
                    reject(e)
                }
            })
        }
        if (this.status === 'pending') {
            return new MyPromise((resolve, reject) => {
                this.onResolvedCallback.push((value) => {
                    try {
                        let result = onResolved(this.data)
                        if (result instanceof MyPromise) {
                            result.then(resolve, reject)
                        }
                        resolve(result)
                    } catch (e) {
                        reject(e)
                    }
                })
                this.onRejectedCallback.push((reason) => {
                    try {
                        let result = onRejected(this.data)
                        if (result instanceof MyPromise) {
                            result.then(resolve, reject)
                        }
                        resolve(result)
                    } catch (e) {
                        reject(e)
                    }
                })
            })
        }
    }
    catch(onRejected) {
        return this.then(null, onRejected)
    }
    all(iterators) {
        let count = 0
        let len = iterator.length
        let res = []
        return new MyPromise((resolve, reject) => {
            for (const i in iterators) {
                MyPromise.resolve(iterators[i])
                    .then((data) => {
                        res[i] = data
                        if (++count === len) {
                            resolve(res)
                        }
                    })
                    .catch(e => {
                        reject(e)
                    })
            }
        })
    }
    race(iterators) {
        return new MyPromise((resolve, reject) => {
            for (const p of iterators) {
                MyPromise.resolve(p)
                    .then((res) => {
                        resolve(res)
                    })
                    .catch(e => {
                        reject(e)
                    })
            }
        })
    }
}

使用fo of来遍历可迭代对象

let obj = {
    a: 1,
    b: 2,
    [Symbol.iterator]: function*(){
        yield 'iterator obj 1';
        yield 'iterator obj 2';
        yield 'iterator obj 3';
    }
}

Promise.myAll = function(iterator){
    return new Promise((resolve, reject) => {
        let arr = []
        let total = 0
        let isDone = false
        function success(res){
            if(isDone){ 
                return
            }
            arr.push(res)
            total--
            if(total <= 0) {
                isDone = true
                resolve(arr)
            }
        }
        function faild(e){
            if(isDone){ 
                return
            }
            isDone = true
            reject(e)
        }
        // 如果不是可迭代对象自会抛出错误
        // 要兼容es6以下版本的需要判断是否为数组、字符串?
        for(let value of iterator){
            total++
            Promise.resolve(value).then(success, faild)
        }
    })
}
testPromiseAll('abcdef')
testPromiseAll([1,2,3,4,5])
testPromiseAll(new Map([[1, 'Map1'], [2,'Map2']]))
testPromiseAll(new Set(['set1', 'set2']))
testPromiseAll([1,2,3,4,5])
testPromiseAll([sleep(100), sleep(200)])
testPromiseAll([sleep(100), sleep(200, true)])
testPromiseAll(obj)

function testPromiseAll(iterotor){
    Promise.all(iterotor).then(res => {
        console.log('Promise.all  ', res)
    }).catch(e => {
        console.log('Promise.all  ', e);
    })
    Promise.myAll(iterotor).then(res => {
        console.log('Promise.myAll error', res);
    }).catch(e => {
        console.log('Promise.myAll error', e);
    })
}
function sleep(time = 500, isFaild = false){
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            isFaild ? reject(new Error('mock error' + time)) : resolve('time: ' + time)
        }, time)
    })
}
commented
Promise.all = (arr) => {
  if (!Array.isArray(arr)) {
    throw new TypeError("参数要是数组!");
  }
  var valuses = [];

  return new Promise((resolve, reject) => {
    for (let i = 0; i < arr.length; i++) {
      // Promise.resolve()处理,确保每一个都是promise实例
      Promise.resolve(arr[i]).then(
        (val) => {
          valuses[i] = val;
          if (valuses.length === arr.length) resolve(valuses);
        },
        (err) => reject(err)
      );
    }
  });
};
commented
myPromise.prototype.all = function(params) {
  if (!(params instanceof Array)) {
    throw new Error('错误');
  }
  return new Promise((resolve, reject) => {
    let res = [];
    for (let i = 0; i < params.length; i++) {
      params[i].then((data) => {
        res[i] = data;
        if (res.length === params.length) {
          resolve(res);
        }
      }).catch((err) => {
        reject(err);
      });
    }
  });
}
//  传入一个数组,等数组的全部成功之后,返回一个Promise对象,成功回调全部返回的数组
  Promise.myAll(arr) {
    //   用于接收所有返回值
    let result = [];
    // 每次调用addData 这个index会加1 用index和传入数组的length比较 来解决异步函数的问题
    let index = 0;
    return new MyPromise((resolve, reject) => {
      // 将数组中每一项添加到result数组中
      function addData(key, value) {
        result[key] = value;
        index++;
        if (index === arr.length) {
          resolve(result);
        }
      }
      for (let index = 0; index < arr.length; index++) {
        let current = arr[index];
        // 需要判断数组中的每一项是promise还是普通值
        if (current instanceof MyPromise) {
          // promise 对象
          current.then(
            (value) => addData(i, value),
            (reason) => reject(reason)
          );
        } else {
          //普通值
          addData(i, current);
        }
      }
    });
  }

1、入参校验
2、保证执行为promise
3、保证执行结果的顺序

Promise.myAll = function (arr) {
  if (!Array.isArray(arr)) {
    throw new TypeError(`param is not Array`)
  }
  return new Promise((resolve, reject) => {
    let len = arr.length;
    let result = []
    let count = 0
    if (len === 0) {
      return resolve(result)
    }
    for (let i in arr) {
      Promise.resolve(arr[i]).then(data => {
        result[i] = data
        count++
        if (count === len) {
          resolve(result)
        }
      }).catch(e => {
        reject(e)
      })
    }
  })
}
function _PromissAll(promises) {
  if (!Array.isArray(promises)) {
    throw new TypeError('argument must be a array');
  }
  return new Promise((resolve, reject) => {
    let promiseCount = 0;
    let promiseNum = promises.length;
    let result = [];
    for (let i = 0; i < promiseNum; i++) {
      Promise.resolve(promises[i])
        .then(res => {
          promiseCount++;
          result[i] = res;
          if (promiseCount === promiseNum) {
            return resolve(result);
          }
        })
        .catch(e => {
          reject(e);
        });
    }
  });
}
Promise.all = function (promiseArr) {
    if (!Array.isArray(promiseArr)) {
        throw new TypeError('not array');
    }
    return new Promise((resolve, reject) => {
        let i = 0;
        let result = [];
        let len = promiseArr.length;
        let count = len;

        function resolver(index) {
            return function (value) {
                resolveAll(index, value);
            }
        }
        function rejecter(reason) {
            reject(reason);
        }
        function resolveAll(index, value) {
            result[index] = value;
            if (--count === 0) {
                resolve(result);
            }
        }

        for (; i < len; i++) {
            promiseArr[i].then(resolver(i), rejecter);
        }
    })
}
function PromiseAll(promises) {
  return new Promise((resolve, reject) => {
    let resultCount = 0
    let promiseLen = Promise.length // 传入的promise个数
    let results = new Array(promiseLen) // 存放返回结果

    for (let i = 0; i < promiseLen; i++) {
      promises[i].then(value => {
        resultCount++;
        results[i] = value
        if (resultCount === promiseLen) {
          return resolve(results)
        }
      }, error => {
        reject(error)
      })
    }
  })
}
commented
function promiseAll(promises) {
  if (promises == null) {
    throw new TypeError('cannot read Symbol.iterator of undefined')
  }

  let res = []
  let index = 0
  return new Promise((resolve, reject) => {

    if (promises.length == 0) {
      resolve([])
    }

    for (let i = 0; i < promises.length; i++) {
      let p = null
      //原始值
      if (isOriginValue(promises[i])) {
        p = handleOriginValue(promises[i])
      } else {
        //promise
        p = promises[i]
      }
      
      p
      .then(value => {
        res.push(value)
    
        if (++index == promises.length) {
          resolve(res)
        }
      })
      .catch(value => {
        reject(value)
      })

    }
  });
}
function isOriginValue(originValue) {
  return !/Promise]$/.test(Object.prototype.toString.call(originValue)) 
}

function handleOriginValue(originValue) {
  return Promise.resolve(originValue)
}

///////////测试

promiseAll([
  Promise.resolve(),
  3, 
  4,
  Promise.resolve(3), 
  Promise.reject(2), 
  // Promise.reject(6),
  Promise.resolve(4)
])
.then(res => console.log('resolve', res))
.catch(rej => console.log('reject', rej)) //reject 2

let p = promiseAll([
  Promise.resolve(),
  new Promise((resolve, reject) => setTimeout(resolve, 1000))
  ]);
  setTimeout(console.log, 0, p); // Promise <pending>
  p.then(() => setTimeout(console.log, 0, 'all() resolved!'));

promiseAll([]) 
.then(res => console.log('resolve', res)) // []
.catch(rej => console.log('reject', rej))
js
	class allReduce {
				constructor(){
					this.index=0;
				}
				reduceTime(arr){
					const _self=this;
					return  setTimeout(function(){
						_self.all(arr)
					},0)
				}
				all(val){
					const _self=this;
					if(!Array.isArray(val)) {
						throw new Error('参数必须是数组');
						return
					}
					if(val.length==this.index) {
						console.log('结束');
						return
					}
					try{
						val[_self.index]();
						_self.reduceTime(val)
					}catch(e){
						_self.reduceTime(val)
					}
					this.index++;
				}
			}
			let promis=new allReduce();
			promis.all([function(){console.log(ss)}, async function(){ let n = await 10; console.log("11 ",n)},function(){console.log("22")},async function(){ let n = await 10; console.log("33 ",n),function(){console.log("44")}}])
// 请实现 Promise.all

Promise.all2 = function (promises) {
    if (!Array.isArray(promises)) {
        throw new Error('all 中必须是数组')
    }

    return new Promise((resolve, reject) => {
        let resolvedCount = 0;
        const resolvedValues = new Array(promises.length)
        const promisesNum = promises.length

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

            Promise.resolve(promises[i]).then(res => {
                resolvedCount++;
                resolvedValues[i] = res

                if (resolvedCount === promisesNum) {
                    resolve(resolvedValues)
                }
            }, reason => {
                reject(reason)
            })

        }
    })
}

function timer(time, val) {
    return new Promise((resolve, reject) => {
        console.time(val)
        setTimeout(() => {
            console.timeEnd(val)
            resolve(val)
        }, time);
    })
}

var promises = [
    timer(1200, 'xiaoming'),
    timer(3000, 'xiaohong'),
    timer(2000, 'xiaohuang'),
    timer(1500, 'xiaosan'),
    3]

console.time('all')
Promise.all2(promises).then(arr => {
    console.timeEnd('all')
    console.log(arr)
})

// xiaoming: 1202.260986328125 ms
// xiaosan: 1501.62109375 ms
// xiaohuang: 2008.06005859375 ms
// xiaohong: 3000.2119140625 ms
// all: 3001.406982421875 ms
// ["xiaoming", "xiaohong", "xiaohuang", "xiaosan", 3]