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

第十八题:请实现 Promise.all #23

Closed
KieSun opened this issue Mar 30, 2021 · 32 comments
Closed

第十八题:请实现 Promise.all #23

KieSun opened this issue Mar 30, 2021 · 32 comments

Comments

@KieSun
Copy link
Owner

KieSun commented Mar 30, 2021

请实现 Promise.all

去答题

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

@learnRy
Copy link

learnRy commented Mar 31, 2021

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)
      })
    })
  })
}

@QuXiaoMing
Copy link

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]

@QuXiaoMing
Copy link

QuXiaoMing commented Mar 31, 2021

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 返回结果顺序不对

@goldEli
Copy link

goldEli commented Mar 31, 2021

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"]

@huangpingcode
Copy link

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+规范

@XINXINP
Copy link

XINXINP commented Mar 31, 2021

  • 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

@yancongwen
Copy link

yancongwen commented Mar 31, 2021

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)
        })
    })
}

@l0ng09
Copy link

l0ng09 commented Mar 31, 2021

// 请实现 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);
      }
    });
  });
};

@pandaomeng
Copy link

代码实现

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

@turkyden
Copy link

turkyden commented Mar 31, 2021

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 判断是否为数组

@qsnote
Copy link

qsnote commented Mar 31, 2021

刚好最近试着封装了下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}))
        })
    }

@Chrisyjs
Copy link

    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)
    })

@makejun168
Copy link

实现一个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 但是感觉不太优雅而且容易出问题

@xihun
Copy link

xihun commented Mar 31, 2021

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);
            })
        })
        
    })
}

@muzishuiji
Copy link

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

@dorothyLee56
Copy link

dorothyLee56 commented Mar 31, 2021

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));
    });
  });
};

@niices
Copy link

niices commented Mar 31, 2021

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"]
});

@louwenqiang
Copy link

louwenqiang commented Mar 31, 2021

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处理实现
}
}

@DaisyX-BOT
Copy link

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 暂时无法实现

@teefing
Copy link

teefing commented Mar 31, 2021

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
})

@monadaa
Copy link

monadaa commented Mar 31, 2021

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)
                    })
            }
        })
    }
}

@huangpingcode
Copy link

使用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)
    })
}

@docterlei
Copy link

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)
      );
    }
  });
};

@ByeLe
Copy link

ByeLe commented Mar 31, 2021

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);
      });
    }
  });
}

@chen870370470
Copy link

//  传入一个数组,等数组的全部成功之后,返回一个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);
        }
      }
    });
  }

@mengzhe510
Copy link

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)
      })
    }
  })
}

@AbigaiL533
Copy link

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);
        });
    }
  });
}

@xt1995726
Copy link

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);
        }
    })
}

@yiyu66
Copy link

yiyu66 commented Mar 31, 2021

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)
      })
    }
  })
}

@yxlazy
Copy link

yxlazy commented Mar 31, 2021

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))

@SunshineZJJ
Copy link

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")}}])

@vandvassily
Copy link

// 请实现 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]

@KieSun KieSun closed this as completed Sep 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests