像结识了一位新朋友一样,最近开始学习了promise。一开始接触到这个名词的时候也在脑海中想,promise是到底是做什么的呢。那么下面跟我一起来认识一下promise把。
首先来了解一下promise的含义
简单来说,promise是一种异步流程的控制手段,比传统的回调函数解决方案更合理和简洁。它解决了传统回调函数方式产生的回调地狱的问题。ES6将其写进了语言标准,统一了语法,原生提供了Promise。
下面我们来看一个简单的例子:
有这么一个场景,想做一道菜:首先要去买菜,买完菜之后才能洗菜,洗完菜之后才能切菜,切完之后才能炒菜,转换成js如下:
function A(callback){ setTimeout(function(){ callback("菜买好了"); }, 1000);}function B(callback){ setTimeout(function(){ callback("菜洗好了"); }, 2000);}function C(callback){ setTimeout(function(){ callback("菜切好了"); }, 3000);} function D(callback){ setTimeout(function(){ callback("菜炒好了"); }, 3000);} 复制代码
- 传统的回调函数方式是
A(function(res){ console.log(res); B(function(res){ console.log(res); C(function(res){ console.log(res); C(function(res){ console.log(res); console.log("菜炒好啦"); }); }); });});复制代码
这就是传说中的回调地狱,实际的场景嵌套的层级可能还更多。这种代码非常不易于理解,而且代码难以维护。 而promise就非常适合这种场景,上面的代码用promise实现
function A() { return new Promise(function (resolve, reject) { setTimeout(function(){ resolve("菜买好了"); }, 1000); });}function B() { return new Promise(function (resolve, reject) { setTimeout(function(){ resolve("菜洗好了"); }, 2000); });}function C() { return new Promise(function (resolve, reject) { setTimeout(function(){ resolve("菜切好了"); }, 2000); });}function D() { return new Promise(function (resolve, reject) { setTimeout(function(){ resolve("菜炒好了"); }, 2000); });}A().then(function(res) { console.log(res); return B();}).then(function(res) { console.log(res); return C();}).then(function(res) { console.log(res); return D();}).then(function(res) { console.log(res); console.log("菜炒好了");});复制代码
可见Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了。
深入理解promise
Promise对象可以理解为一次将要执行的操作(常常被用于异步操作),使用了 Promise 对象之后可以用一种链式调用的方式来组织代码,让代码更加直观。promise 实现链式调用返回的并不是this而是一个新的promise。
promise(承诺)有三种状态,分别是
- resolve (成功)
- reject (失败)
- pending (等待态)
状态改变: Promise对象的状态改变,只有两种可能: 从pending变为reject。 从pending变为resolve 如果一旦promise成功了就不能失败,相反也是一样的。所以这两种情况只要发生,状态就凝固了,不会再变了,这时就称为resolved(已定型)。
每一个promise的实例上都有一个then方法,then方法中有两个参数,一个参数叫成功的函数 ,一个是失败的函数。 then方法定义:then(fulfilledAHandler, errorHandler),对应着Promise的resolve, reject。
一个promise可以then多次
let p = new Promise((resolve,reject)=>{ resolve('成功');});p.then(data=>{ console.log(data);});p.then(data=>{ console.log(data);})p.then(data => { console.log(data);});复制代码
promise中只要发生错误,就会执行失败态。如果返回的是一个普通值就会走到写一个then中的成功回调,如果有错误产生会走失败的回调。
- Promise只有一个参数 叫excutor执行器,默认new时就会调用
let p = new Promise((resolve,reject)=>{ // 默认promise中的executor是同步执行的 resolve('买');});// then方法是异步调用的,事件环p.then((value)=>{ // value成功 console.log(1);},(err)=>{ // err失败});console.log(2);复制代码
执行结果,2 1。
promise可以处理并发任务
promise用promise.all方法做并发调用,当所有Promise 对象都变为完成态或失败态时,回调将被执行。
let fs = require('fs'); // fileSystemfunction read(url) { return new Promise((resolve, reject) => { fs.readFile(url, 'utf8', function (err, data) { if (err) reject(err); resolve(data); }) })}Promise.all([read('1.txt'),read('2.txt')]).then((data)=>{ console.log(data); },err=>{ console.log(err); });复制代码
promise.race赛跑,处理多请求只取最快的
Promise.all([read('1.txt'),read('2.txt')]).then((data)=>{ console.log(data); },err=>{ console.log(err); });复制代码
读取哪个文件快,返回哪个文件的结果
Promise.resolve() 返回一个成功的promise
Promise.reject() 返回一个失败的promise
promise.reject('123').then(null,data=>{ console.log(data);});复制代码
最后用es6语法简单实现一下Promise的原理
class Promise { constructor(executor) { this.status = 'pending'; this.value = undefined; this.reason = undefined; let resolve = value => { if (this.status ==='pending'){ this.status = 'resolved'; this.value = value; } } let reject = reason => { if (this.status === 'pending') { this.status = 'rejected'; this.reason = reason; } } try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFufilled,onRjected){ if(this.status === 'resolved'){ onFufilled(this.value); } if(this.status === 'rejected'){ onRjected(this.reason); } }}module.exports = Promise复制代码