ES6中Promise的使用方法实例总结


Posted in Javascript onFebruary 18, 2020

本文实例讲述了ES6中Promise的使用方法。分享给大家供大家参考,具体如下:

在javascript中,代码是单线程执行的,对于一些比较耗时的IO操作,都是通过异步回调函数来实现的。

但是这样会存在一个问题,当下一个的操作需要上一个操作的结果时,我们只能把代码嵌到上一个操作的回调函数里,这样一层嵌一层,最终形成回调地狱。

$.get('/login.php', function (login) {
  $.get('/user.php', function (user) {
    $.get('/info.php', function (info) {
      //代码就这样一层嵌一层,不够直观,维护也麻烦
    });
  });
});

为了解决这种问题,ES6中就提供了Promise方法来解决这种问题。

Promise是一个构造函数,通过它,我们可以创建一个Promise实例对象。

let p = new Promise(function (resolve, reject) {
  setTimeout(() => {
    console.log('OK');
    resolve('OK');
  }, 1000);
});

Promise构造函数接受一个函数作为参数,这个函数有两个参数,resolve和reject。

resolve函数是将Promise的状态设置为fulfilled(完成),reject函数是将Promise的状态设置为rejected(失败)。

上述代码,我们并没有进行任何调用,当运行时,间隔1秒后输出了'OK'。所以这里需要注意,我们通常使用Promise时,需要在外层再包裹一层函数。

let p = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log('OK');
      resolve('OK');
    }, 1000);
  });
};
p();

上面的代码p();返回的是一个Promise实例对象,Promise对象上有 then() , catch() , finally() 方法。

then方法有两个参数,onFulfilled和onRejected,都是函数。

onFulfilled用于接收resolve方法传递过来的数据,onRejected用于接收reject方法传递过来的数据。

let p = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      if (Math.random() > 0.5) {
        resolve('OK');
      } else {
        reject('ERR');
      }
    }, 1000);
  });
};
p().then(function (data) {
  console.log('fulfilled', data);
}, function (err) {
  console.log('rejected', err);
});

then()方法总是会返回一个Promise实例,这样我们就可以一直调用then()。

在then方法中,你既可以return 一个具体的值 ,还可以return 一个Promise对象。

如果直接return的是一个数据,那then方法会返回一个新Promise对象,并以该数据进行resolve。

let p = function () {
  return new Promise(function (resolve, reject) {
    resolve(1);
  });
};
p().then(function (data) {
  console.log(`第 ${data} 次调用`);
  //注意这里直接返回的值
  //then会创建一个新的Promise对象,并且以返回的值进行resolve
  //那么该值会被下面的then方法的onFulfilled回调拿到
  return ++data;
}).then(function (data) {
  console.log(`第 ${data} 次调用`);
  return ++data;
}).then(function (data) {
  console.log(`第 ${data} 次调用`);
  return ++data;
});

如果返回的是一个Promise对象,请看下面代码。

let p = function () {
  return new Promise(function (resolve, reject) {
    resolve(1);
  });
};
p().then(function (data) {
  console.log(`第 ${data} 次调用`);
  return new Promise(function (resolve, reject) {
    resolve(++data);
  });
}).then(function (data) {
  console.log(`第 ${data} 次调用`);
  return new Promise(function (resolve, reject) {
    resolve(++data);
  });
}).then(function (data) {
  console.log(`第 ${data} 次调用`);
  return new Promise(function (resolve, reject) {
    resolve(++data);
  });
});

其实效果与直接返回值的是一样的。

即然then()可以进行链式操作,那我们最早之前的回调地狱写法,就可以通过它进行改进了。

function login() {
  return new Promise(function (resolve, reject) {
    $.get('/login.php', function (result) {
      resolve(result);
    });
  });
}
function user(data) {
  return new Promise(function (resolve, reject) {
    $.get('/user.php', function (result) {
      resolve(result);
    });
  });
}
function info(data) {
  return new Promise(function (resolve, reject) {
    $.get('/info.php', function (result) {
      resolve(result);
    });
  });
}
login().then(function (data) {
  console.log('处理login');
  //把login异步处理获取的数据,传入到下一个处理中。
  return user(data);
}).then(function (data) {
  console.log('处理user');
  //把user异步处理获取的数据,传入到下一个处理中。
  return info(data);
}).then(function (data) {
  console.log('处理info');
});

这样修改后,回调地狱层层嵌套的结构就变的清晰多了。上述代码是伪代码。

Promise对象还有一个catch方法,用于捕获错误,该方法与 then(null, onRejected) 等同,是一个语法糖。

let p = function () {
  return new Promise(function (resolve, reject) {
    resolve('开始');
  });
};
p().then(function (data) {
  console.log('1');
  return new Promise(function (resolve, reject) {
    reject('错误1');
  });
}).then(function (data) {
  console.log('2');
  return new Promise(function (resolve, reject) {
    reject('错误2');
  });
}).then(function (data) {
  console.log('3');
  return new Promise(function (resolve, reject) {
    reject('错误3');
  });
}).catch(function (reason) {
  console.log(reason);
});

注意,一旦操作中有错误发生,则会进入到catch中,后面的操作将不再执行。

Promise对象内部自带了try catch,当代码运行时错误,会自动以错误对象为值reject,并最终被catch捕获。

let p = function () {
  return new Promise(function (resolve, reject) {
    resolve('开始');
  });
};
p().then(function (data) {
  //注意这里打印了一个未定义的变量
  console.log(a);
}).catch(function (reason) {
  //这里会捕获到错误
  console.log('rejected');
  console.log(reason);
});

Promise还提供了,all(),race(),reject(),resolve()等在构造函数上的方法,调用这些方法并不需要实例化对象。

all()方法,可以让我们并行的执行异步操作,直到所有操作完成了,才执行回调。

function fn1() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn1');
    }, 1000);
  });
}
function fn2() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn2');
    }, 2000);
  });
}
function fn3() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn3');
    }, 3000);
  });
}
//all会等待所有操作完成,会把所有操作的结果放到一个数组中,传给then。
Promise.all([fn1(), fn2(), fn3()]).then(function (data) {
  console.log(data);
});

race()方法是谁先处理完,就以谁为准,把最先处理完的结果传给then。

function fn1() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn1');
    }, 1000);
  });
}
function fn2() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn2');
    }, 2000);
  });
}
function fn3() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn3');
    }, 3000);
  });
}
//race是以谁先处理完,就以谁为准,fn1最先处理完,那fn1的结果会传给then
//注意这里fn2和fn3还是会执行,不过不会进入then了
Promise.race([fn1(), fn2(), fn3()]).then(function (data) {
  console.log(data);
});

reject()方法,返回一个带有拒绝原因reason参数的Promise对象。

// Promise.reject('错误')
// 等同于
// new Promise(function(resolve, reject) {
//   reject('错误');
// });
let p = Promise.reject('错误');
p.then(function (data) {
}).catch(function (reason) {
  console.log(reason);
});

resolve()方法,根据传入的值返回一个Promise对象。

//如果传入的参数是普通值,则返回一个新Promise对象,并以该值resolve
let p1 = Promise.resolve('OK');
p1.then(function (data) {
  console.log(data);
});
//如果传入的参数是一个Promise对象,则原封不动的返回该Promise对象
let obj = new Promise(function (resolve, reject) {
  resolve('我是Promise对象');
});
let p2 = Promise.resolve(obj);
p2.then(function (data) {
  console.log(data);
  console.log(p2 === obj);
});
//如果传入的参数是一个thenable对象(带有then方法),
//会转换成Promise对象,并执行thenable对象的then方法
let then = {
  then(resolve, reject) {
    resolve('我是thenable对象');
  }
}
let p3 = Promise.resolve(then);
p3.then(function (data) {
  console.log(data);
});
//如果什么参数都不传入,则返回状态为resolved的Promise对象
let p4 = Promise.resolve();
p4.then(function (data) {
  console.log(data);
}).catch(function (reason) {
  console.log(reason);
});

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

更多关于JavaScript相关内容可查看本站专题:《JavaScript操作DOM技巧总结》、《JavaScript页面元素操作技巧总结》、《JavaScript事件相关操作与技巧大全》、《JavaScript查找算法技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript错误与调试技巧总结》

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
Jquery+JSon 无刷新分页实现代码
Apr 01 Javascript
Jquery中dialog属性小记
Sep 03 Javascript
jquery选择器-根据多个属性选择示例代码
Oct 21 Javascript
判断输入是否为空,获得输入类型的JS代码
Oct 30 Javascript
jQuery图片轮播滚动切换代码分享
Apr 20 Javascript
学习JavaScript正则表达式
Nov 13 Javascript
Javascript中的Prototype到底是什么
Feb 16 Javascript
Javascript点击其他任意地方隐藏关闭DIV实例
Jun 21 Javascript
JS中绑定事件顺序(事件冒泡与事件捕获区别)
Jan 24 Javascript
js中编码函数:escape,encodeURI与encodeURIComponent详解
Mar 21 Javascript
webpack vue项目开发环境局域网访问方法
Mar 20 Javascript
axios使用拦截器统一处理所有的http请求的方法
Nov 02 Javascript
React中获取数据的3种方法及优缺点
Feb 18 #Javascript
JavaScript canvas绘制渐变颜色的矩形
Feb 18 #Javascript
JavaScript canvas绘制折线图
Feb 18 #Javascript
node+multer实现图片上传的示例代码
Feb 18 #Javascript
JavaScript canvas绘制圆弧与圆形
Feb 18 #Javascript
javascript中的with语句学习笔记及用法
Feb 17 #Javascript
JS实现百度搜索框关键字推荐
Feb 17 #Javascript
You might like
解析htaccess伪静态的规则
2013/06/18 PHP
Laravel中validation验证 返回中文提示 全局设置的方法
2019/09/29 PHP
文本框input聚焦失焦样式实现代码
2012/10/12 Javascript
jquery如何判断表格同一列不同行input数据是否重复
2014/05/14 Javascript
判断window.onload是否多次使用的方法
2014/09/21 Javascript
JavaScript定时显示广告代码分享
2015/03/02 Javascript
jQuery仅用3行代码实现的显示与隐藏功能完整实例
2015/10/08 Javascript
JavaScript动态插入CSS的方法
2015/12/10 Javascript
获取input标签的所有属性的方法
2016/06/28 Javascript
JS实现太极旋转思路分析
2016/12/09 Javascript
AngularJS服务service用法总结
2016/12/13 Javascript
elemetUi 组件--el-upload实现上传Excel文件的实例
2017/10/27 Javascript
对 Vue-Router 进行单元测试的方法
2018/11/05 Javascript
微信小程序--获取用户地理位置名称(无须用户授权)的方法
2019/04/29 Javascript
JS表格的动态操作完整示例
2020/01/13 Javascript
echarts.js 动态生成多个图表 使用vue封装组件操作
2020/07/19 Javascript
在vue中获取wangeditor的html和text的操作
2020/10/23 Javascript
仅用500行Python代码实现一个英文解析器的教程
2015/04/02 Python
Python将一个CSV文件里的数据追加到另一个CSV文件的方法
2018/07/04 Python
win8.1安装Python 2.7版环境图文详解
2019/07/01 Python
django使用admin站点上传图片的实例
2019/07/28 Python
Python 操作mysql数据库查询之fetchone(), fetchmany(), fetchall()用法示例
2019/10/17 Python
浅析Python 中的 WSGI 接口和 WSGI 服务的运行
2020/12/09 Python
python多线程爬取西刺代理的示例代码
2021/01/30 Python
Python tkinter之ComboBox(下拉框)的使用简介
2021/02/05 Python
微信端html5页面调用分享接口示例
2018/03/14 HTML / CSS
雷蛇美国官网:Razer
2020/04/03 全球购物
实习生自我评价
2014/01/18 职场文书
组织生活会发言材料
2014/12/15 职场文书
平安家庭事迹材料
2014/12/20 职场文书
成品仓管员岗位职责
2015/04/01 职场文书
2015党建工作简报
2015/07/21 职场文书
MySQL 存储过程的优缺点分析
2021/05/20 MySQL
详解Python生成器和基于生成器的协程
2021/06/03 Python
mysq启动失败问题及场景分析
2021/07/15 MySQL
单机多实例部署 MySQL8.0.20
2022/05/15 MySQL