ES6原生Promise的全部方法介绍(附一道应用场景题目)

JS的ES6已经出来好久了,做为前端工程师若是对此还不熟悉有点说不过去。不过若是要问,Promise原生的api一共有哪几个?好像真的能够难倒一票人,包括我本身也忽略了其中一个不经常使用的API Promise.race。咱们来瞧一下MDN对Promise的讲解: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise前端

 

来看一下Promise的方法和prototype列表:api

【1】Promise.prototype.catch 在Promise被reject的时候触发数组

【2】Promise.prototype.then 在Promise被resolve的时候触发浏览器

【3】Promise.prototype.finally 不管Promise是否resolve仍是reject,都会触发。请注意,这个是一个比较新的特性,大部分浏览器并无实现该特性。Promise.prototype.finally目前的浏览器兼容性列表以下:前端工程师

该特性还在Stage 3阶段,等到在浏览器中大面积普及,估计要好久之后了。能够采用第三方库的实现,好比bluebird。async

【4】Promise.resolve 直接返回一个已经resolve的Promise实例ide

【5】Promise.reject 直接返回一个已经reject的Promise实例函数

【6】Promise.all 传入一个Promise列表(常见的是由Promise组成的数组),只有当列表中全部的Promise都resolve时,该Promise才会resolve,只要有一个reject,则该Promise会reject。url

【7】Promise.race 传入一个Promise列表,其中第一个resolve的Promise会使得该Promise.race 最终 resolve,若是第一个完成的Promise是reject的,那么Promise.race最终也reject(其实就是和跑的最快的那个Promise结果同样~)。spa

 

其实Promise的原生API也就这么几个,其中Promise.all和Promise.race是最容易被忽略的两个。我以前曾经不太熟悉Promise.race这个API致使实现一个需求卡住了好久。咱们来经过一个小的练习熟悉该API的用法吧。

 

附上一道题目:

假设目前有1000个url下载连接,已经存储在数组url[1000]中(即url = ['http://example.com/video1.mp3', ...., 'http://example.com/video1000.mp3']),并且已经有一个函数function download,输入一个url连接,返回一个Promise,该Promise在连接下载完成的时候resolve,下载失败则reject。可是咱们要求,任意时刻,同时下载的连接数量不能够超过10个。请写一段代码实现这个需求,要求尽量快速地将该1000个连接下载完成。

思路:声明一个长度为10的,由Promise组成的数组,用Promise.race作汇总,只要检测到1个Promise resolve了,那就赶忙把那个Promise替换成一个新的再继续下载。

const TotalTaskCount = 1000; // 一共有1000个连接
const MaxConcurrency = 10; // 同时下载的连接数最大不超过10
const url = [...]; // 1000个下载连接组成的数组
const download = function (urlStr) {
  // 返回Promise, 当下载完成的时候resolve
}

Answer:

let todoList = [];
let nextIndex = 0;
for (let j = 0; j < MaxConcurrency; j++) {
  let task = download(url[nextIndex]).then(() => {return j}); // 注意这里resolve的值是任务在todoList的脚标,方便咱们在Promise.race以后找到完成的任务脚标
  todoList.push(task);
  nextIndex++;
}

const run = async function(todo) {
  let index = await Promise.race(todo); // 这里index等于Promise.race第一个完成的任务的脚标
  if (nextIndex < TotalTaskCount) {
    todo[index] = download(url[nextIndex]).then(() => {return index;}); // 一旦有一个任务完成,立刻把他替换成一个新的任务,继续下载
    nextIndex++;
  }
  await run(todo);
}

run(todoList);
相关文章
相关标签/搜索