科协科普网站建设,泰州网站建设方案优化,做网站的一般要多少钱,小制作的制作过程Promise是ES6最重要的特性之一#xff0c;今天来系统且细致的研究一下Promise的用法以及原理。
按照我往常的理解#xff0c;Promise是一个构造函数#xff0c;有all、resolve、reject、then、catch等几个方法#xff0c;一般情况下#xff0c;在涉及到异步操作时才会用到…Promise是ES6最重要的特性之一今天来系统且细致的研究一下Promise的用法以及原理。
按照我往常的理解Promise是一个构造函数有all、resolve、reject、then、catch等几个方法一般情况下在涉及到异步操作时才会用到Promise。
所以我接下来先new一个Promise对象并在其中进行一些异步操作
// 使用Promise的时候一般会把它包裹在一个函数中并在函数的最后返回这个Promise对象
function runPro()(var a new Promise((resolve, reject) {setTimeout(() {console.log(work done!);resolve(success);}, 1000);});return a;
)
runPro()在上面的代码中Promise的构造函数接收一个箭头函数作为参数这个箭头函数又有两个参数分别是resolve和reject我在这个箭头函数中使用setTimeout进行了一些异步操作异步操作中执行了resolve方法并给resolve方法传了一个字符串‘success’作为参数。
执行这段代码会发现等待了1秒钟后因为我在setTimeout中设置的等待时间是1000毫秒输出了‘work done!’。
这时候并没有发现Promise有什么特别的作用而且resolve和reject这两个的作用也并没有体现出来。
之前我们说过Promise这个构造函数上有then、catch方法在上面的代码片段中runPro函数最后return了一个Promise对象所以我们可以在runPro函数执行完成之后使用then对Promise对象进行进一步的操作
runPro().then((res) {console.log(then:, res);//TODO something
});输出结果 在runPro返回的Promise对象上直接调用then方法then方法接收一个函数作为参数A并且这个箭头函数也会接收一个参数B这个参数B的值就是前面代码中resolve方法所传递的字符串‘success’。
执行代码会在1秒后首先输出‘work done’紧接着输出‘then: success’。
这个时候就可以简单的体现出来Promise的作用了在前面的代码中then方法就像是Promise的回调函数当Promise中的异步操作执行完之后通过链式调用的方式执行回调函数。 这里的关键点就在于链式调用上当实际使用中遇见多层回调的情况时Promise的强大之处才能够体现出来
function runPro2(){var a new Promise((resolve, reject) {setTimeout(() {resolve(success);console.log(this is runPro2);}, 1000);});return a;
};function runPro3(){var a new Promise((resolve, reject) {setTimeout(() {resolve(success);console.log(this is runPro3);}, 1000);});return a;
};runPro().then(() {return runPro2();
}).then(() {return runPro3();
}).then(() {console.log(all done)
})到这里为止大概已经明白了Promise是一个在异步操作过程中等待其中异步操作完成之后执行其回调函数的一种结构体。但是其中的原理还是模糊不清其中resolve和reject这两个参数还没有搞清楚只知道在前面的几个代码片段中都调用了resolve函数resolve是做什么的并没有体现出来。
关于resolve和reject我以前的理解是Promise中的异步操作执行成功后调用resolve函数异步操作执行失败后调用reject函数后来发现这种理解其实是不准确的。 在理解这两个函数的正确作用之前我们首先要知道Promise一个重要的特性状态
Promise的状态
一个Promise对象的当前状态必须为以下三种状态中的一种等待Pending、完成Fulfilled、拒绝Rejected。
Pending 异步操作完成之前Promise处于等待状态这时候的Promise可以迁移至Fulfilled或者Rejected。Fulfilled 异步操作完成之后Promise可能从Pending状态迁移至Fulfilled状态Fulfilled状态的Promise必须拥有一个不可变的终值并且Fulfilled状态的Promise不能迁移为其他状态。Rejected: 异步操作完成之后Promise可能从Pending状态迁移至Rejected状态Rejected状态的Promise必须拥有一个不可变的拒绝原因并且Rejected状态的Promise不能迁移为其他状态。
了解了Promise的三种状态之后我们再来说说resolve和reject这两个函数的作用
resolve函数将Promise设置为Fulfilled状态reject函数将Promise设置为Rejected状态。设置为Fulfilled或者rejected状态后即表示Promise中的异步操作执行完成这时程序就会执行then回调函数。resolve和reject函数传递的参数将由then函数中的箭头函数接收。
实际上理解Promise的关键点就在于这个状态通过维护状态、传递状态的方法来进行及时的回调。
所以如下面代码所示当使用Promise进行异步操作的时候其中有几个关键点需要特别注意
在一个函数中new了一个Promise对象之后函数的最后必须把这个Promise对象return出来否则这个函数就无法使用then函数进行回调异步操作中必须执行resolve或者reject函数否则这个Promise一直处于Pending状态代码就不会执行它的回调函数。
function runPro(){var a new Promise((resolve, reject) {setTimeout(() {resolve(resolve);console.log(this is runPro);}, 1000);});return a;
}runPro().then((res) {console.log(res);
})同样的道理当异步操作执行失败时代码通过执行reject函数的方式将Promise的状态设置为Rejected并返回一个拒绝原因
function runPro(item){var a new Promise((resolve, reject) {setTimeout(() {if(item 18) {console.log(item 大于 18);resolve(一切正常);}else {console.log(item 小于 18);reject(18电影不允许放映);}}, 1000);});return a;
}runPro(13)
.then((res) {console.log(resolve:,res);
},(rej) {console.log(reject:, rej);
})我们给runPro函数传递不同的参数runPro接受参数后进行一个异步的判断如果这个参数的值小于18执行reject函数反之则执行resolve函数异步操作完成之后执行then回调函数这里的回调函数可以接收两个箭头函数作为参数分别对应了resolve函数的回调和reject函数的回调这两个箭头函数可以分别拿到resolve和reject传递的参数。
如下面截图所示分别给runPro传递两个不同值后得到了两种不同的结果
catch函数的用法
在Promise中catch函数可以替代reject函数使用用来指定接收reject的回调
function runPro(item){var a new Promise((resolve, reject) {setTimeout(() {if(item 18) {console.log(item 大于 18);resolve(一切正常);}else {console.log(item 小于 18);reject(18电影不允许放映);}}, 1000);});return a;
}runPro(13)
.then((res) {console.log(resolve:,res);
})
.catch((rej) {console.log(catch:, rej);
})如上面代码所示对调函数then只有一个箭头函数作为参数这种情况下这个箭头函数就被指定用来接收resolve函数的回调而reject函数的回调则被catch函数来接收 这个地方使用catch函数来接收reject的回调有一个优点当前面的then回调函数中出现位置错误时catch函数可以对错误信息进行处理而不会导致代码报错。这个原理和常用的try/catch语句相同。
function runPro(item){var a new Promise((resolve, reject) {setTimeout(() {if(item 18) {console.log(item 大于 18);resolve(一切正常);}else {console.log(item 小于 18);reject(18电影不允许放映);}}, 1000);});return a;
}
runPro(19)
.then((res) {console.log(adc); // 这里的adc是一个未定义的变量当代码执行到这里时会抛出Error信息导致代码卡死console.log(resolve:,res);
}, (rej) {console.log(reject:,rej);
});
runPro(19)
.then((res) {console.log(abc); // 这里的abc是一个未定义的变量但是由于后边使用.catch函数进行了异常捕获所以程序不会报错。而且错误原因也会作为参数传递到后面.catch函数的参数中console.log(resolve:,res);
})
.catch((rej) {console.log(catch:, rej);
})all函数 / race函数并行异步操作
Promise的all函数和race函数都提供了并行异步操作的能力二者的区别在于,当这些并行的异步操作耗时不同时all函数是在所有的异步操作都执行完之后才会执行而race函数则会在第一个异步操作完成之后立即执行。
function runPro1(){var a new Promise((resolve, reject) {setTimeout(() {resolve(success);console.log(this is runPro1);}, 1000);});return a;
}
function runPro2(){var a new Promise((resolve, reject) {setTimeout(() {resolve(success);console.log(this is runPro2);}, 2000);});return a;
};function runPro3(){var a new Promise((resolve, reject) {setTimeout(() {resolve(success);console.log(this is runPro3);}, 3000);});return a;
};Promise.all([runPro1(), runPro2(), runPro3()])
.then((res) {console.log(all:, res);
})function runPro1(){var a new Promise((resolve, reject) {setTimeout(() {resolve(success);console.log(this is runPro1);}, 1000);});return a;
}
function runPro2(){var a new Promise((resolve, reject) {setTimeout(() {resolve(success);console.log(this is runPro2);}, 2000);});return a;
};function runPro3(){var a new Promise((resolve, reject) {setTimeout(() {resolve(success);console.log(this is runPro3);}, 3000);});return a;
};Promise.races([runPro1(), runPro2(), runPro3()])
.then((res) {console.log(all:, res);
})如上两个代码片段所示all函数和race都接收一个数组作为参数这个数组中的值就是我们要进行并行执行的异步操作。这里我们同样使用then函数作为异步操作完成的回调函数。
同时我们通过console输出发现在race函数的回调函数开始执行的时候另外两个没有执行完成的异步操作并没有停止依旧在执行。