Advanced-Frontend / Daily-Interview-Question

我是依扬(木易杨),公众号「高级前端进阶」作者,每天搞定一道前端大厂面试题,祝大家天天进步,一年后会看到不一样的自己。
https://muyiy.cn/question/
27.4k stars 3.29k forks source link

第 89 题:设计并实现 Promise.race() #140

Open yygmind opened 5 years ago

lhyt commented 5 years ago
Promise._race = promises => new Promise((resolve, reject) => {
    promises.forEach(promise => {
        promise.then(resolve, reject)
    })
})
suki-chan commented 5 years ago
Promise.myrace = function(iterator) {
    return new Promise ((resolve,reject) => {
        try {
            let it = iterator[Symbol.iterator]();
            while(true) {
                let res = it.next();
                console.log(res);
                if(res.done) break;
                if(res.value instanceof Promise) {
                    res.value.then(resolve,reject);
                } else {
                    resolve(res.value)
                }

            }
        } catch (error) {
            reject(error)
        }
    }) 
}
CHristopherkeith commented 5 years ago

基本和上面的例子差不多,不同点是每个传入值使用Promise.resolve转为Promise对象,兼容非Promise对象

const _race = (p)=>{
    return new Promise((resolve, reject)=>{
        p.forEach((item)=>{
            Promise.resolve(item).then(resolve, reject)
        })
    })
}
Mini-Web commented 5 years ago
Promise.miniRace = function(promises) {

    return new Promise((rs,rj)=>{
        try {
            // 检查输入值是否可迭代
            iteratorCheck(promises)

            const len = promises.length;
            let promiseStatusChanged = false;

            for (let i = 0; i < len; i++) {
                if (promiseStatusChanged)
                    break;
                // 使用 Promise.resolve 包装 thenable 和 非thenable 值
                Promise.resolve(promises[i]).then(rs).catch(rj).finally(()=>{
                    promiseStatusChanged = true
                }
                )
            }

        } catch (e) {
            rj(e)
        }

    }
    )
}

    function iteratorCheck(data) {
        if (!data[Symbol.iterator] || typeof data[Symbol.iterator] !== 'function') {
            const simpleType = typeof data;
            let errMsg = simpleType
            if (['number', 'boolean'].includes(simpleType) || data === null) {
                errMsg += ` ${String(data)}`
            }

            throw new TypeError(`${errMsg} is not iterable (cannot read property Symbol(Symbol.iterator))`)
        }
    }
pre1ude commented 5 years ago
const PromiseRace = (iterable)=>{
    return new Promise((resolve, reject) => {
      for (const p of iterable) {
        Promise.resolve(p).then(resolve).catch(reject)
      }
    })
  }
GoodLuckAlien commented 5 years ago
 Promice.race= function(PromiseArr){
        let hasResolve = false
        return new PromiceA((resolve,reject)=>{
            PromiseArr.forEach(promiseItem=>{
                promiseItem.then(res=>{
                    !hasResolve && resolve(res)
                    hasResolve = true
                },(err)=>{
                   !hasResolve && reject(err)
                })
            })
        })
    }
yaodongyi commented 5 years ago
let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
    }, 100)
})
let p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('failed')
    }, 500)
})

/**
 * 实现一个race
 * @param {Array} array 
 */
let race = function (array) {
    return new Promise((resolve, reject) => {
        let len = array.length;
        while (len--) {
            array[len].then(res => {
                return resolve(res);
            }).catch(err => {
                return reject(err);
            })
        }
    })
}
// 调用
race([p1, p2]).then(res => {
    console.log(res);
}).catch(err => {
    console.error(err);
})
liyikun commented 5 years ago

Promise._race = function(Promises) { return new Promise((resolve, reject) => { Promises.forEach(p => p.then(resolve, reject)) }) }

aeolusheath commented 4 years ago
Promise.race = function(...list) {
  return new Promise((resolve, reject) => {
    for (let item of list) {
      let p = item.then ? p : Promise.resolve(p) 
      // p.then(value => {
      //   resolve(value)
      // }).catch(err => {
      //   reject(err)
      // })
      p.then(resolve, reject)
    }
  })
}
bbrucechen commented 4 years ago
function promiseRace(promiseArr) {
  return new Promise((resolve,reject) => {
    for(let i = 0;i < promiseArr.length;i++) {
      promiseArr[i].then(res => resolve(res),rej => reject(rej))
    }
  })
}

const pro1 = new Promise((res,rej) => {
  setTimeout(() => {
    res('我是1')
  },1000)
})

const pro2 = new Promise((res,rej) => {
  setTimeout(() => {
    res('我是2')
  },10000)
})

const pro3 = new Promise((res,rej) => {
  setTimeout(() => {
    res('我是3')
  },300)
})

const race = promiseRace([pro1,pro2,pro3])
race.then(res => {
  console.log(res)
})
jinfang12345 commented 4 years ago
let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
    }, 100)
})
let p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('failed')
    }, 500)
})

/**
 * 实现一个race
 * @param {Array} array 
 */
let race = function (array) {
    return new Promise((resolve, reject) => {
        let len = array.length;
        while (len--) {
            array[len].then(res => {
                return resolve(res);
            }).catch(err => {
                return reject(err);
            })
        }
    })
}
// 调用
race([p1, p2]).then(res => {
    console.log(res);
}).catch(err => {
    console.error(err);
})

resolve()前 没必要return 吧

random-yang commented 4 years ago
function promiseRace(promises) {
    return new Promise((res, rej) => {
        promises.forEach(promise => promise.then(res).catch(rej));
    })
}
xiaochen-01 commented 4 years ago
Promise.protopype.race = (promises) => {
    return new Promise((resolve, reject) => {
        promises.forEach(promise => promise.then(resolve, reject))
    });
}
tjwyz commented 4 years ago
    static race(arr) {
        // 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。
        return new PromiseA((resolve, reject) => {
            arr.forEach((item)=>{
                // “状态的变更是单向的”
                item.then(resolve, reject);
            })
        })
    }
wang-qiqi commented 4 years ago

有点像电路的并行,只要有一个开关打开的就可以接通了。

chun1hao commented 4 years ago
Promise.race = function(promises){
    return new Promise((resolve, reject)=>{
        for(let i of promises){
            Promise.resolve(i).then(resolve, reject)
        }
    })    
}
slogeor commented 3 years ago
function testRace() {
    function getPromise(i, timeout = 0) {
        const random = Math.random();
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                random > 0.5 ? reject(`reject: ${random} - ${i}`) : resolve(`resolve: ${random} - ${i}`)
            }, timeout)
        })
    }

    Promise.race2 = function (promises) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                // promises[i] 可能是普通值
                Promise.resolve(promises[i]).then((data) => {
                    resolve(data);
                }, (err) => {
                    reject(err)
                });
            }
        });
    }

    const p1 = getPromise(1, 200);
    const p2 = getPromise(2, 300);
    const p3 = getPromise(3, 100);

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

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

testRace();

Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。

可以通过设置 getPromise 函数的第二个参数,验证race2 输出结果与 race是否一致

ghost commented 3 years ago
Promise._race = function(iterator) {
            return new Promise((resolve, reject) => {
                for (let item of iterator) {
                    Promise.resolve(item).then((data) => {
                        resolve(data);
                    }).catch(err => {
                        reject(err);
                    });
                }
            });
        }
jackluson commented 3 years ago

Tip:

  1. Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝

  2. 判断函数参数是否是可迭代的(很多答案都忽略了)

const isIterable = (data, reject) => {
  const type = typeof data;
  if (!data[Symbol.iterator]) {
    if (reject) {
      reject(
        new TypeError(
          `${type} ${data} is not iterable (cannot read property Symbol(Symbol.iterator))`
        )
      );
    } else {
      throw new TypeError(
        `${type} ${data} is not iterable (cannot read property Symbol(Symbol.iterator))`
      );
    }
  }
};
Promise.myRace = function (promises) {
  return new Promise((resolve, reject) => {
    isIterable(promises, reject); // 判断是否是迭代对象
    const promiseArray = [...promises];
    promiseArray.forEach((pr) => {
      if (!(pr instanceof Promise)) {
        pr = Promise.resolve(pr);
      }
      pr.then(resolve, reject);
    });
  });
};

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "one");
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 100, "two");
});

Promise.myRace([promise1, promise2])
  .then((value) => {
    console.log("value", value);
    // Both resolve, but promise2 is faster
  })
  .catch((err) => {
    console.log("err", err);
  });
PastelSubliminal commented 2 years ago
Promise.race = function(values){
  return new Promise((resolve,reject)=>{
    for(let i = 0 ; i< values.length;i++){
      Promise.resolve(values[i]).then(resolve,reject)
    }
  })
}
Yangfan2016 commented 2 years ago

Promise.race = function (proms) {
    return new Promise((rs, rj) => {
        proms.forEach(p => {
            Promise.resolve(p).then(rs).catch(rj);
        })
    });
}
lastertd commented 1 year ago
    static race<T extends Iterable<any>>(args: T) {     //约定T从属于Iterable类型
        return new MyPromise((resolve, reject) => {
            const promise = Array.from(args);   //将args转化为数组类型
            if (promise.length === 0){      //假设数组长度为0, 则永远处于pending状态
                return
            }
            /**会执行所有resolve或者reject,
             * 但是Promise内部状态只会变化一次(pending->fulfilled | pending->rejected)
             * 所以只会保留第一次状态改变
             */
            for (let i = 0; i < promise.length; i++) {
           //用Promise.resolve包裹一层, 可以将非Promise对象转为Promise对象
                MyPromise.resolve(promise[i]).then(data => {
                    resolve(data);
                },reason => {
                    reject(reason)
                })
            }
        })
    }
Dylan0916 commented 1 year ago
Promise.myRace = (promises) => {
  const _promises = Array.isArray(_promises) ? _promises : [promises];

  return new Promise((resolve, reject) => {
    _promises.forEach((promise) => {
      Promise.resolve(promise).then(resolve, reject);
    });
  });
};
negativeentropy9 commented 4 months ago
Promise.fakeRace = function (list) {
  return new Promise((resolve, reject) => {
    list.forEach((promise) => {
      promise.then(resolve, reject);
    });
  });
};

function createPromise(i) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      // resolve(i);
      reject(i);
      clearTimeout(timer);
    }, i * 100);
  });
}

Promise.fakeRace([createPromise(1), createPromise(2)]).then(
  (data) => console.log("fullfilled", data),
  (e) => console.log("rejected", e)
);