Daily-Interview-Question icon indicating copy to clipboard operation
Daily-Interview-Question copied to clipboard

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

Open yygmind opened this issue 5 years ago • 24 comments

yygmind avatar Jun 12 '19 14:06 yygmind

Promise._race = promises => new Promise((resolve, reject) => {
	promises.forEach(promise => {
		promise.then(resolve, reject)
	})
})

lhyt avatar Jun 12 '19 14:06 lhyt

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

suki-chan avatar Jun 14 '19 02:06 suki-chan

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

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

CHristopherkeith avatar Jul 18 '19 15:07 CHristopherkeith

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

Mini-Web avatar Jul 19 '19 13:07 Mini-Web

const PromiseRace = (iterable)=>{
    return new Promise((resolve, reject) => {
      for (const p of iterable) {
        Promise.resolve(p).then(resolve).catch(reject)
      }
    })
  }

pre1ude avatar Jul 24 '19 14:07 pre1ude

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

GoodLuckAlien avatar Aug 11 '19 08:08 GoodLuckAlien

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

yaodongyi avatar Sep 17 '19 04:09 yaodongyi

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

liyikun avatar Oct 13 '19 03:10 liyikun

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

aeolusheath avatar Oct 20 '19 04:10 aeolusheath

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

bbrucechen avatar Dec 26 '19 02:12 bbrucechen

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 吧

jinfang12345 avatar Jan 14 '20 09:01 jinfang12345

function promiseRace(promises) {
    return new Promise((res, rej) => {
        promises.forEach(promise => promise.then(res).catch(rej));
    })
}

random-yang avatar Apr 15 '20 09:04 random-yang

Promise.protopype.race = (promises) => {
    return new Promise((resolve, reject) => {
        promises.forEach(promise => promise.then(resolve, reject))
    });
}

xiaochen-01 avatar Apr 22 '20 14:04 xiaochen-01

	static race(arr) {
		// 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。
		return new PromiseA((resolve, reject) => {
			arr.forEach((item)=>{
				// “状态的变更是单向的”
				item.then(resolve, reject);
			})
		})
	}

tjwyz avatar Jul 16 '20 13:07 tjwyz

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

wang-qiqi avatar Jul 22 '20 08:07 wang-qiqi

Promise.race = function(promises){
    return new Promise((resolve, reject)=>{
        for(let i of promises){
            Promise.resolve(i).then(resolve, reject)
        }
    })    
}

chun1hao avatar Sep 16 '20 03:09 chun1hao

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是否一致

slogeor avatar Oct 24 '20 06:10 slogeor

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

ghost avatar Feb 24 '21 00:02 ghost

Tip:

  1. Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝
  1. 判断函数参数是否是可迭代的(很多答案都忽略了)
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);
  });

jackluson avatar Aug 24 '21 09:08 jackluson

Promise.race = function(values){
  return new Promise((resolve,reject)=>{
    for(let i = 0 ; i< values.length;i++){
      Promise.resolve(values[i]).then(resolve,reject)
    }
  })
}

PastelSubliminal avatar Feb 22 '22 23:02 PastelSubliminal


Promise.race = function (proms) {
    return new Promise((rs, rj) => {
        proms.forEach(p => {
            Promise.resolve(p).then(rs).catch(rj);
        })
    });
}

Yangfan2016 avatar Aug 22 '22 14:08 Yangfan2016

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

lastertd avatar Sep 06 '23 04:09 lastertd

Promise.myRace = (promises) => {
  const _promises = Array.isArray(_promises) ? _promises : [promises];

  return new Promise((resolve, reject) => {
    _promises.forEach((promise) => {
      Promise.resolve(promise).then(resolve, reject);
    });
  });
};

Dylan0916 avatar Sep 06 '23 06:09 Dylan0916