前端JavaScript之Promise

目录
  • 1、什么是Promise
  • 2、基本用法
  • 3、Promise的方法
    • 3.1 Promise.prototype.then()
    • 3.2 Promise.prototype.catch()
    • 3.3 Promise.prototype.finally()
    • 3.4 Promise.all()
    • 3.5 Promise.race()
    • 3.6 Promise.allSettled()
    • 3.7 Promise.any()
    • 3.8 Promise.resolve()
    • 3.9 Promise.reject()
  • 4、简单场景

1、什么是Promise

Promise 是异步编程的一种解决方案。ES6中已经提供了原生 Promise 对象。一个 Promise 对象会处于以下几种状态(fulfilledrejected两种状态一旦确定后不会改变):

  • 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled): 意味着操作成功完成。
  • 已拒绝(rejected): 意味着操作失败。

2、基本用法

Promise 对象是一个构造函数,用来创建 Promise 实例,它接收两个参数 resolve reject

  • resolve 的作用是将 Promise 对象的状态从 pending 变为 fulfilled ,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
  • reject 的作用是将 Promise 对象的状态从 pending 变为 rejected ,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
const promise = new Promise(function(resolve, reject) {
  // ...
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise 实例生成以后,使用 then 方法分别指定 fulfilled 状态和 rejected 状态的回调函数。

  • then 接收两个参数,第一个是 Promise 对象的状态变为 fulfilled 时的回调函数,第二个是状态变为 rejected 时的回调函数。
  • catch 接收 Promise 对象的状态变为 rejected 时的回调函数。
promise.then(function (value){
 // ....
},function (err){
 // .... err
})

promise.then(function (value){
 // ....
}).catch(function (err){
    // ....
})

3、Promise的方法

3.1 Promise.prototype.then()

then 方法是定义在原型对象 Promise.prototype 上,前面说过,它接收两个可选参数,第一个参数是 fulfilled 状态的回调函数,第二个参数是 rejected 状态的回调函数。

then 方法返回的是一个新的 Promise 实例,方便我们采用链式写法。比如 then 后面接着写 then ,当第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。这种链式方式可以很方便的指定一组按照次序调用的回调函数。

loadData().then(function (value){
    return 3
}).then(function (num){
    console.log("ok", num) // 3
})

3.2 Promise.prototype.catch()

catch 方法是用于指定发生错误时的回调函数。如果异步操作抛出错误,状态就会变为 rejected ,就会调用 catch() 方法指定的回调函数,处理这个错误。

const promise = new Promise(function(resolve, reject) {
  throw new Error('unkonw error'); // 抛出错误状态变为 -> reject
});
const promise = new Promise(function(resolve, reject) {
  reject('unkonw error') // 使用reject()方法将状态变为 -> reject
});
promise.catch(function(error) {
  console.log(error);
});

Promise 对象的错误会一直向后传递,直到被捕获为止。比如下面代码: catch 会捕获 loadData 和两个 then 里面抛出的错误。

loadData().then(function(value) {
  return loadData(value);
}).then(function(users) {

}).catch(function(err) {
  // 处理前面三个Promise产生的错误
});

如果我们不设置 catch() ,当遇到错误时 Promise 不会将错误抛出外面,也就是不会影响外部代码执行。

const promise = new Promise(function(resolve, reject) {
   resolve(a) // ReferenceError: a is not defined
});
promise.then(function(value) {
  console.log('value is ', value)
});
setTimeout(() => { console.log('code is run') }, 1000); // code is run

3.3 Promise.prototype.finally()

finally() 方法不管 Promise 对象最后状态如何,都会执行的操作。下面是我们使用 Promise 的一个常规结构。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

3.4 Promise.all()

Promise.all() 方法可以将多个 Promise 实例包装成一个新的 Promise 实例返回。

const promise = Promise.all([p1, p2, p3]);

promise 状态来依赖于“传入的 promise ”。

  • 只有当所有“传入的 promise ”状态都变成 fulfilled ,它的状态才会变成 fulfilled ,此时“传入的 promise ”返回值组成一个数组,传递给 promise 的回调函数。
  • 如果“传入的 promise ”之中有一个被 rejected ,新 promise 的状态就会变成 rejected ,此时第一个被 reject promise 的返回值,会传递给 promise 的回调函数。
const promises = [1,2,3,4].map(function (id) {
  return loadData(id);
});

Promise.all(promises).then(function (users) {
  // ...
}).catch(function(err){
  // ...
});

3.5 Promise.race()

Promise.race() 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

Promise.race() 方法的参数与 Promise.all() 方法一样。

const promise = Promise.race([p1, p2, p3]);

Promise.all() Promise.race() 对比:

Promise.all() ,如果所有都执行成功则返回所有成功的 promise 值,如果有失败则返回第一个失败的值。
Promise.race() ,返回第一个执行完成的 promise 值,它可能是fulfilledrejected状态。
这两个方法的使用场景

场景一:用户登录社交网站主页后,会同时异步请求拉取用户信息,关注列表,粉丝列表,我们需要保证所有数据请求成功再进行渲染页面,只要有一个数据不成功就会重定向页面,这里可以使用 Promise.all

function initUserHome() {
  Promise.all([
  new Promise(getMe),
  new Promise(getFollows),
  new Promise(getFans)
])
    .then(function(data){
     // 显示页面
  })
    .catch(function(err){
    // .... 重定向页面
  });
};

initUserHome();

场景二:假如我们在做一个抢票软件,虽然请求了很多卖票渠道,每次只需返回第一个执行完成的 Promise ,这里可以使用 Promise.race

function getTicket() {
  Promise.race([
  new Promise(postASell),
  new Promise(postBSell),
  new Promise(postCSell)
])
    .then(function(data){
     // 抢票成功
  })
    .catch(function(err){
    // .... 抢票失败,重试
  });
};

getTicket();

3.6 Promise.allSettled()

使用 Promise.all() 时,如果有一个 Promise 失败后,其它 Promise 不会停止执行。

const requests = [
  fetch('/url1'),
  fetch('/url2'),
  fetch('/url3'),
];

try {
  await Promise.all(requests);
  console.log('所有请求都成功。');
} catch {
  console.log('有一个请求失败,其他请求可能还没结束。');
}

有的时候,我们希望等到一组异步操作都结束了,再进行下一步操作。这时就需要使用 Promise.allSettled() ,的它参数是一个数组,数组的每个成员都是一个 Promise 对象,返回一个新的 Promise 对象。它只有等到参数数组的所有 Promise 对象都发生状态变更(不管是 fulfilled 还是 rejected ),返回的 Promise 对象才会发生状态变更。

const requests = [
  fetch('/url1'),
  fetch('/url2'),
  fetch('/url3'),
];

await Promise.allSettled(requests);
console.log('所有请求完成后(包括成功失败)执行');

3.7 Promise.any()

只要传入的 Promise 有一个变成 fulfilled 状态,新的 Promise 就会变成 fulfilled 状态;如果所有传入的 Promise 都变成 rejected 状态,新的 Promise 就会变成 rejected 状态。

Promise.any() Promise.race() 差不多,区别在于 Promise.any() 不会因为某个 Promise 变成 rejected 状态而结束,必须等到所有参数 Promise 变成 rejected 状态才会结束。

回到 Promise.race() 多渠道抢票的场景,如果我们需要保证要么有一个渠道抢票成功,要么全部渠道都失败,使用 Promise.any() 就显得更合适。

function getTicket() {
  Promise.any([
  new Promise(postASell),
  new Promise(postBSell),
  new Promise(postCSell)
])
    .then(function(data){
     // 有一个抢票成功
  })
    .catch(function(err){
    // .... 所有渠道都失败了
  });
};

getTicket();

3.8 Promise.resolve()

Promise.resolve() 方法将现有对象转换为 Promise 对象。等价于下面代码:

new Promise(resolve => resolve(1))

传入的参数不同,处理

  • 参数 Promise 实例,它将不做任何修改、原封不动地返回这个实例。
  • 参数 thenable 对象,它会将这个对象转为 Promise 对象,然后就立即执行 thenable 对象的 then() 方法。
let thenable = {
  then: function(resolve, reject) {
    resolve(1);
  }
};
  • 参数是普通值,返回一个新的 Promise 对象,状态为 resolved
const promise = Promise.resolve(1);

promise.then(function (value) {
  console.log(value) // 1
});
  • 无参数,直接返回一个 resolved 状态的 Promise 对象。

3.9 Promise.reject()

Promise.reject(reason) 方法也会返回一个新的 Promise 实例,该实例的状态为 rejected

const promise = Promise.reject('unkonw error');
// 相当于
const promise = new Promise((resolve, reject) => reject('unkonw error'))

promise.then(null, function (s) {
  console.log(s)
});
// unkonw error

4、简单场景

异步加载图片:

function loadImageAsync(url) {
  return new Promise(function(resolve, reject) {
   const image = new Image();
    image.onload  = resolve;
    image.onerror = reject;
    image.src = url;
  });
}

请求超时处理:

//请求
function request(){
    return new Promise(function(resolve, reject){
       // code ....
         resolve('request ok')
    })
}

function timeoutHandle(time){
   return new Promise(function(resolve, reject){
        setTimeout(function(){
            reject('timeout');
        }, time);
    });
}

Promise.race([
    request(),
    timeoutHandle(5000)
])
.then(res=>{
    console.log(res)
}).catch(err=>{
    console.log(err)// timeout
})

到此这篇关于前端JavaScriptPromise的文章就介绍到这了,更多相关JavaScript Promise内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • js Promise并发控制数量的方法

    目录 问题 背景 思路 & 实现 问题 要求写一个方法控制 Promise 并发数量,如下: promiseConcurrencyLimit(limit, array, iteratorFn) limit 是同一时间执行的 promise 数量,array 是参数数组,iteratorFn 每个 promise 中执行的异步操作. 背景 开发中需要在多个promise处理完成后执行后置逻辑,通常使用Promise.all: Primise.all([p1, p2, p3]).then((res)

  • JavaScript如何利用Promise控制并发请求个数

    一.场景 假设现在有这么一种场景:现有 30 个异步请求需要发送,但由于某些原因,我们必须将同一时刻并发请求数量控制在 5 个以内,同时还要尽可能快速的拿到响应结果. 如图所示: 上图这样的排队和并发请求的场景基本类似,窗口只有三个,人超过三个之后,后面的人只能排队了. 二.串行和并行 串行:一个异步请求完了之后在进行下一个请求 并行:多个异步请求同时进行 串行举例: var p = function () { return new Promise(function (resolve, reje

  • JS异步堆栈追踪之为什么await胜过Promise

    概述 async/await和Promise的根本区别在于await fn()暂停当前函数的执行,而promise.then(fn)在将fn调用添加到回调链后,继续执行当前函数. const fn = () => console.log('hello') const a = async () => { await fn() // 暂停 fn 的执行 } // 调用 a 时,才恢复 fn 的执行 a() // "hello" const promise = Promise.r

  • Javascript异步编程之你真的懂Promise吗

    前言 在异步编程中,Promise 扮演了举足轻重的角色,比传统的解决方案(回调函数和事件)更合理和更强大.可能有些小伙伴会有这样的疑问:2020年了,怎么还在谈论Promise?事实上,有些朋友对于这个几乎每天都在打交道的"老朋友",貌似全懂,但稍加深入就可能疑问百出,本文带大家深入理解这个熟悉的陌生人-- Promise. 基本用法 语法 new Promise( function(resolve, reject) {...} /* executor */ ) 构建 Promise

  • JS异步代码单元测试之神奇的Promise

    前言 写这篇文章的起因是在写单元测试时,做形如下测试时 new Promise((resolve, reject) => reject(1)).then().catch(err => { console.log(err) }) async function jestTest () { await Promise.resolve().then() console.log('这个时候catch预期已经被调用,且输出日志') } jestTest() 无法使用await将测试代码恰好阻塞到catch

  • 详解JavaScript Promise和Async/Await

    概述 一般在开发中,查询网络API操作时往往是比较耗时的,这意味着可能需要一段时间的等待才能获得响应.因此,为了避免程序在请求时无响应的情况,异步编程就成为了开发人员的一项基本技能. 在JavaScript中处理异步操作时,通常我们经常会听到 "Promise "这个概念.但要理解它的工作原理及使用方法可能会比较抽象和难以理解. 四个示例 那么,在本文中我们将会通过实践的方式让你能更快速的理解它们的概念和用法,所以与许多传统干巴巴的教程都不同,我们将通过以下四个示例开始: 示例1:用生

  • JS如何为promise增加abort功能

    目录 概述 promise race方法 重新包装promise AbortController  Axios插件自带取消功能 概述 Promise只有三种状态:pending.resolve.reject,一个异步的承诺一旦发出,经历等待(pending)后,最终只能为成功或者失败,中途无法取消(abort). 为promise提供abort功能的思路有两种: 手动实现abort,触发取消后,异步回来的数据直接丢弃(手动实现,比较稳妥) 使用原生方法AbortController中断请求(实验

  • JS 9个Promise面试题

    1. 多个.catch var p = new Promise((resolve, reject) => { reject(Error('The Fails!')) }) p.catch(error => console.log(error.message)) p.catch(error => console.log(error.message)) 以上代码的输出将会是什么?请选择正确的答案: [ ] 打印一次消息 [x] 打印两次消息 [ ]UnhandledPromiseReject

  • JavaScript使用promise处理多重复请求

    一.为什么要写这个文章? 处理重复请求的文章想必大家也看过了很多,大多数都是分为在response返回之前发现重复请求就return掉的和使用节流/防抖来间接规避用户频繁操作两种版本的.最近在使用的过程的中,发现这两个版本在某些场景下还是有些局限性. 二.问题场景 如图,我这个h5的页面,顶部和底部都要显示这个名片组件.这些名片的信息是通过一个接口来获取的,当这个组件在当前页面被初始化时,就会发生两次重复的请求. 这时会面临几个抉择: 1. 不对重复请求做任何处理. 缺点1:造成不必要的资源浪费

  • 前端JavaScript之Promise

    目录 1.什么是Promise 2.基本用法 3.Promise的方法 3.1 Promise.prototype.then() 3.2 Promise.prototype.catch() 3.3 Promise.prototype.finally() 3.4 Promise.all() 3.5 Promise.race() 3.6 Promise.allSettled() 3.7 Promise.any() 3.8 Promise.resolve() 3.9 Promise.reject()

  • 前端 javascript 实现文件下载的示例

    在 html5 中,a 标签新增了 download 属性,包含该属性的链接被点击时,浏览器会以下载文件方式下载 href 属性上的链接.示例: <a href="https://www.baidu.com" rel="external nofollow" download="baidu.html">下载</a> 1. 前端 js 下载实现与示例 通过 javascript 动态创建一个包含 download 属性的 a

  • javascript中Promise使用详解

    目录 一.首先,要知道为什么要用Promise语法? 二.接着,来了解一下回调地狱(Callback Hell) 三.最后,也是本章的重头戏,Promise的基本使用 (一) resolve函数 (二) rejected函数 (三)Promise的API 1. then 2. catch 3. finally 4. Promise.all 5. Promise.race 四.最后 前言: 做过前端开发的都知道,JavaScript是单线程语言,浏览器只分配给JS一个主线程,用来执行任务,但是每次

  • JavaScript中Promise的使用方法实例

    目录 前言 Promise简介 什么是回调地狱? Promise的特点 创建Promise实例 then方法 resolve 和 reject 的参数传递 then()链式调用 then()的返回值 catch方法 finally方法 Promise的方法 Promise.resolve() Promise.reject() Promise.all() Promise.allSettled() Promise.race() async 和 await async函数函数 await 异步函数的错

  • 理解JavaScript中Promise的使用

    Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doom),绝对是一种糟糕的编程体验.于是便有了 CommonJS 的 Promises/A 规范,用于解决回调金字塔问题.本文先介绍 Promises 相关规范,然后再通过解读一个迷你的 Promises 以加深理解. 什么是 Promise 一个 Promise 对象代表一个目前还不可用,但是在未来的

  • 前端JavaScript彻底弄懂函数柯里化curry

    目录 一.什么是柯里化( curry) 二.柯里化的用途 三.如何封装柯里化工具函数 一.什么是柯里化( curry) 在数学和计算机科学中,柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术. 举例来说,一个接收3个参数的普通函数,在进行柯里化后, 柯里化版本的函数接收一个参数并返回接收下一个参数的函数, 该函数返回一个接收第三个参数的函数. 最后一个函数在接收第三个参数后, 将之前接收到的三个参数应用于原普通函数中,并返回最终结果. 数学和计算科学中的柯里化: // 数

  • 常用的前端JavaScript方法封装

    目录 1.输入一个值,返回其数据类型** 2.数组去重 3.字符串去重 4.深拷贝 浅拷贝 5.reverse底层原理和扩展 6.圣杯模式的继承 7.找出字符串中第一次只出现一次的字母 8.找元素的第n级父元素 9. 返回元素的第n个兄弟节点 10.封装mychildren,解决浏览器的兼容问题 11.判断元素有没有子元素 12.我一个元素插入到另一个元素的后面 13.返回当前的时间(年月日时分秒) 14.获得滚动条的滚动距离 15.获得视口的尺寸 16.获取任一元素的任意属性 17.绑定事件的

  • 前端JavaScript中的反射和代理

    目录 1.什么是反射 2.JavaScript中Reflect 2.1 Reflect.get(target, name, receiver) 2.2 Reflect.set(target, name, value, receiver) 2.3 Reflect.has(obj, name) 2.4 Reflect.deleteProperty(obj, name) 2.5 Reflect.construct(target, args) 2.6 Reflect.setPrototypeOf(obj

  • 关于前端JavaScript ES6详情

    目录 1.简介 1.1 Babel 转码器 1.2 polyfill 2.let 和 const 2.1 let 2.2 const 3.解构 3.1 对象解构 3.2 数组解构 3.3 函数参数解构 3.4 常见场景 4.扩展 4.1 字符串扩展 4.2 函数扩展 4.3 数组扩展 4.4 对象扩展 4.5 运算符扩展 5.for-of 6.小结 1.简介 ES6是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015.ES2016.ES2017语法标准.

随机推荐