React 学习笔记_11(JavaScript 中的Promise)

JaveScript 中的 Promise

Promise的含意

所谓的 "promise" 代表为一个容器,保存着某个未来才会结束的事件(非同步)的结果。

Promise有两个特点 :
1.不受外界影响。Promise有三种状态: "pending(进行中)", "fulfilled(已成功)" , "rejected(以失败)",只有非同步操作的结果才能改变他的状态,其他手段无法改变。

2.状态一旦改变就不会再变化。Promise状态有两种改变 : pending -> fulfilled , pending -> rejected。只要任何一种情况发生就不会再发生变化,此时称为 "resolved(已完成)" ,就算再对她添加callback function也依然会得到这个结果。

基本用法 :

const promise = new Promise(function(resolve,rejected){    if(/* Success */)    {        resolve(value);    }    else    {        reject(error);    }});

Promise接收一个function作为输入参数,该function的两个参数分别是 "resolve" , "reject"

resolve : 当promise从未完成变成成功(pending -> resolved)时调用,将操作的结果作为参数传递。
rejuct : 当promise从未完成变成失败(pending -> reject)时调用,将操作失败的错误报出并传递。

Promise生成后可以使用.then方法分别指定resolved与reject的callback function

promise.then(function(value){    //Success},function(error){    //false});

then可以接受两个callback function作为参数,当promise变为resolved时呼叫第一个function,反之当变成reject时呼叫第二个function。

Example :

timeout = (ms) => {    return new Promise((resolve,reject) =>{            //将"done"当作参数传递给resolve        setTimeout(resolve,ms,"done");    });}//传递给resolve的参数因为操作成功所以可以适用then读取到参数(done)timeout(100).then((value) => {    console.log(value); //done});

若呼叫resolve或是reject时带有参数,那么他们的参数会被传递给callback function。reject的参数通常是error对象,表示发生的错误 ; resolve的参数除了正常的数值之外已可能是另一个promise

const p1 = new Promise(function (resolve, reject) {  // ...});const p2 = new Promise(function (resolve, reject) {  // ...  resolve(p1);});

p1与p2都是promise,但是p2的resolve将p1做为参数,即一个非同步的操作会return另一个非同步的操作,这时p1的状态会传递给p2,也就是说p1决定了p2的状态,若p1的状态是pending,则p2会等待p1的状态改变;若p1已经是resolved或是rejected,那么p2的callback function便会立刻执行。

const p1 = new Promise(function (resolve, reject) {  setTimeout(() => reject(new Error('fail')), 3000)})const p2 = new Promise(function (resolve, reject) {  setTimeout(() => resolve(p1), 1000)})p2  .then(result => console.log(result))  .catch(error => console.log(error))// Error: fail

p1三秒后会变成reject;p2状态在一秒之后会改变,resolve方法返回的是p1,由于p2返回的是另一个promise会导致自己的状态无效,由p1的状态决定了p2的状,所以后面的.then都会变成针对 "p1" 的状态,所以会触发.catch console出Error:fail。

注意!! 若是调用了resolve或reject并不会结束promise的function执行。

new Promise((resolve, reject) => {  resolve(1);  console.log(2);}).then(r => {  console.log(r);});

若是调用了resolve(1)后,后面的console.log(2)仍然会执行并会先被console出来,因为callback function必须等到stack空了后才会执行,所以一般来说后续的操作应该放在.then里面执行,在他们之前加上"return"以防有意外。

new Promise((resolve, reject) => {  return resolve(1);  // 后面不会执行  console.log(2);})

Promise.prototype.then()

为promise添加状态改变时的callback function,第一个参数是resolved状态的callback function,第二的参数(可选)是rejected状态的callback function。

then会return一个新的promise(不是原来的promise),因此可以採用链式的写法,then后面再调用一个then

function timeout(ms) {    return new Promise((resolve, reject) => {        resolve(1);    });}timeout(1000).then((value) => {    console.log(value);    return value + 10; // 将第一个callback的结果return给第二的callback当作输入参数}).then((value) => {    console.log(value);});

Promise.prototype.catch()

catch用于指定发生错误时的callback function,若一个Promise的非同步操作发生错误状态变为rejected,则会调用catch所指定的callback function处理这个错误,若是then方法指定的callback function执行发生错误的话也会被catch捕获到。

promise发生错误 :

function timeout(ms) {    return new Promise((resolve, reject) => {        resolve(AAA); //产生error    });}timeout(1000).then((value) => {    console.log("Success");}).catch((error) =>{    console.log(error)  //ReferenceError: AAA is not defined})

then发生错误 :

function timeout(ms) {    return new Promise((resolve, reject) => {        resolve(1);    });}timeout(1000).then((value) => {    console.log(X); //造成错误}).catch((error) =>{    console.log(error) //ReferenceError: X is not defined})

由于catch可以捕获到promise与之后then的错误,所以建议对于reject来说使用catch,而不使用then的第二个参数。

Promise.prototype.finally()

finally用于不管Promise最后状况为何都会执行的操作。(ES2018加入)

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

不论promise的状态为何都会执行finally指定的callback function。
由于finally不接受任何输入参数,所以无法知道promise的状态为何,这鳔式finally里面的操作式与状态无关的,不依赖promise的执行结果。

Promise.prototype.all()

all用于将多个Promise包装成一个新的Promise。

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

p的状态由p1,p2,p3决定,分成两种情况 :
1.当p1,p2,p3都变成fulfilled时,p才会是fulfilled,此时p1,p2,p3返回一个数组传递给p的callback function。
2.只要p1,p2,p3其中一个变成reject那么p就会变成reject,此时第一个变成reject的的return会传递给P的callback funciton。

Example :

const promises = [2, 3, 5, 7, 11, 13].map(function (id) {  return getJSON('/post/' + id + ".json");});Promise.all(promises).then(function (posts) {  // ...}).catch(function(reason){  // ...});

只有当6个promise的状态都改变成fulfilled后,p的状态才会改变为fulfilled,而若6个promise有其中一个变为reject那p的状态就会变为reject。而当p的状态改变后才会调用后面的callback function。

注意!!如果做为餐数的promise有定义自己的catch那么一旦它变成rejected,并不会触发到all.catch而是自己的catch

const p1 = new Promise((resolve, reject) => {  resolve('hello');}).then(result => result).catch(e => e); //定义自己的catchconst p2 = new Promise((resolve, reject) => {  throw new Error('报错');}).then(result => result).catch(e => e); //定义自己的catchPromise.all([p1, p2]).then(result => console.log(result)).catch(e => console.log(e));

上面的程式中,p1状态会变为resolved而p2的状态会变为reject而进入自己的catch,当p2进入自己的catch后,由于执行完catch后状态会变为resolved,所以对all而言两个promise都是resolved,便不会进入到all.catch指定的callback function中。

Promise.prototype.race()

同样是将多个promise包装成一个新的promise但与all不同。

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

当p1,p2,p3任何一个发生状态改变时,p的状态就会跟着改变,首先改变状态的promise会return一个参数传入p的callback function中。

const p = Promise.race([  fetch('/resource-that-may-take-a-while'),  new Promise(function (resolve, reject) {    setTimeout(() => reject(new Error('request timeout')), 5000)  })]);p.then(console.log).catch(console.error);

上面的程式,若秒之内fatch方法无法返回结果,p的状态就会变成reject(当一个状态改变时,p状态会跟着改变),从而触发catch中的callback function。

Promise.prototype.resolve()

将现有的对象转变为promise

Promise.resolve('foo')// 等价于new Promise(resolve => resolve('foo'))

resolve()的参数有四种 :
1.参数是一个promise : 若promise的参数是一个promise,则不做动作 return 一个promise

2.参数是一个thenable(具有then方法的object)

let thenable = {    then: function(resolve, reject) {        resolve(42);    }};

pormise.resolve会将这个object转为peomise,然后立刻执行thenable的then

let thenable = {    then: function(resolve, reject) {        resolve(42);    }};let p1 = Promise.resolve(thenable);p1.then(function(value) {    console.log(value);  // 42});

上面的程式中,thanable object的then执行后,p1状态就变为resolved,从而执行p1的then的callback function并console出42。

3.参数不具有then的object或根本不是object,则promise.resolve返回一个新的promise状态为resolved

4.不带任何参数,会直接返回一个resolved状态的promise,注意!! resolve()的promise是在本轮event loop结束时才执行,而不是下一轮event loop才执行

setTimeout(function () {  console.log('three');}, 0);Promise.resolve().then(function () {  console.log('two');});console.log('one');// one// two// three

由于setTimeout在下一轮event loop才执行,而promise.resolved()是在本轮的event loop结束时执行,console.log("one")则是直接放入stack中立刻执行,所以最先输出。

Promise.prototype.reject()

Promise.reject(reason)会return一个新的promise,而该promise的状态为rejected。
注意!!Promise.reject的参数会做完reject的理由,变成后续catch的参数。

const thenable = {  then(resolve, reject) {    reject('出错了');  }};Promise.reject(thenable).catch(e => {  console.log(e === thenable)  console.log(e);  console.log(thenable);})/************     true    { then: [Function: then] }    { then: [Function: then] }*************/

参考资料 :
ECMAScript 6 入门


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章