关于Promise的简单了解

1.什么是Promise

简单的说“Promise对象用于表示一个异步操作的最终状态(完成或者失败)以及其返回的值”

关于异步与同步,简单地说可以以同步任务会阻塞程序执行(alter、for、.......),而异步任务不会阻塞程序执行(setTimeout 、fs.readFile 、......)

2.首先我们比较传统的回调方式与promise

预备知识点:

  • then()方法是异步执行。就是当.then()前的方法执行完后再执行then()内部的程序,这样就避免了,数据没获取到等的问题。

  • 箭头函数

var    f = (参数)=>{ 代码块}
var    ff = (x,y)=>{ return x+y }

*******************************
箭头函数的一个用处是简化回调函数。

// 正常函数写法
[1,2,3].map(function (x) {
  return x * x;
});

// 箭头函数写法
[1,2,3].map(x => x * x);
  • resolve()是指Promise成功调用时执行的事件
// 比较传统的回调方式与promise

// -------------------------------------------------------
// 回调

// 方法 用于请求数据(模拟)
// function f(cb) {
// 	setTimeout(function() {
// 		cb && cb();
// 	}, 1000);
// }

// f(function() {
// 	console.log(1);

// 	f(function() {
// 		console.log(2);

// 		f(function() {
// 			console.log(3);

// 			f(function() {
// 				console.log(4);

// 				f(function() {
// 					console.log(5);

// 					f(function() {
// 						console.log(6);
// 					});
// 				});
// 			});
// 		});
// 	});
// });

// -------------------------------------------------------
// promise

// 方法 用于请求数据(模拟)
function f() {
	return new Promise(resolve => {
		setTimeout(function() {
			resolve();
		}, 2000);
	})
}

f()
	.then(function() {
		console.log(1);
		 return f();//返回后会以这个promise实例去执行,只是单单输出1后就马上输出2
	})
	.then(function() {
		console.log(2);
	});
	.then(function() {
		console.log(4);
		return f();
	})
	.then(function() {
		console.log(3);
		return f();
	})
	.then(function() {
		console.log(5);
		return f();
	})
	.then(function() {
		console.log(6);
	});

 传统的回调方式不仅层层叠叠,而且不容易时修改回调顺序。在这个环境下,产生了Promise,它正是为了解决多重嵌套回调函数而提出的,使用Promise后,回调函数条理更加清晰,同时如果当需要修改调用顺序时,只需要挪动下then函数的位置就可以了。

3.认识对比回调与Promise的流程控制

预备知识:

  • 模板字符串(使用反引号的字符串)
  • 箭头函数

html代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    #el {
      width: 100px;
      background: green;
      transition: all 1s;
      color: white;
      line-height: 100px;
      text-align: center;
      font-size: 40px;
    }
  </style>
</head>
<body>
  <div id="el">哦</div>
  <button id="btn">开始</button>
  <script src="./main.js"></script>
</body>
</html>

JS代码

// 动画

// function moveTo(el, x, y, cb) {
// 	el.style.transform = `translate(${x}px, ${y}px)`;
// 	setTimeout(function() {
// 		cb && cb();
// 	}, 1000);
// }

// let el = document.querySelector('div');

// document.querySelector('button').addEventListener('click', e => {
// 	moveTo(el, 100, 100, function() {
// 		moveTo(el, 200, 200, function() {
// 			moveTo(el, 30, 20, function() {
// 				moveTo(el, 100, 300, function() {
// 					moveTo(el, 130,20, function() {
// 						moveTo(el, 0, 0, function() {
// 							console.log('移动结束!');
// 						});
// 					});
// 				});
// 			});
// 		});
// 	});
// });

// promise


function moveTo(el, x, y) {
	return new Promise(resolve => {
		el.style.transform = `translate(${x}px, ${y}px)`;
		setTimeout(function() {
			resolve(); 
		}, 1000);
	});
}


let el = document.querySelector('div');

document.querySelector('button').addEventListener('click', e => {
	moveTo(el, 100, 100)
		.then(function() {
			console.log('第一次移动');
			return moveTo(el, 200, 200);
		})
		.then(function() {
			console.log('第二次移动');
		})
		.then(function() {
			console.log('第二次移动');
		});
});

4.信任问题

Promise的信任问题很少书籍有做说明,我也只是初步了解。大家可以通过下面的代码感受下resolve()只可以执行一次。

// 信任问题

// 第三方的某个库
function method(cb) {
  // 未按所想的预期执行回调
  setTimeout(function() {
    // 讲道理应该是现在该调用回调了
    cb && cb();
    // 但是?? 好像这个库有bug啊 emm 被多调用了一次
    cb && cb();
  }, 1000);
}

// promise一但被确定为成功或者失败 就不能再被更改

function method() {
  return new Promise(resolve => {
    setTimeout(function() {
      // 成功
      resolve();
      resolve();
    }, 1000);
  });
}


// 控制反转

function method(cb) {
  // 未按所想的预期执行回调
  setTimeout(function() {
    // 执行回调 但是添油加醋
    cb && cb.call({a: 1, b: 2});
  }, 1000);
}

function method(cb) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(); // 调用的resolve全为自己所写书写的流程 很大程度上改善了反转控制的问题
    }, 1000);
  });
}

5.错误处理

通过之前的例子我们可以感受到resolve()正确处理的效果,下面讲讲的是reject()错误处理的应用。

function f(val) {
  return new Promise((resolve, reject) => {
    if (val) {
      resolve({ name: '小明' });//只可以传递一个参数
    } else {
      reject('404');
    }
  }); 
}

// then(resolve, reject)
// then方法中的第二个回调 失败时候做的事

// f(false)
//   .then((data) => {
//     console.log(data)
//   }, e => {
//     console.log(e);
//   })

//----------------------------------------
// catch
// 使用实例的catch方法 可以捕获错误

// f(true)
//   .then(data => {
//     console.log(data);
//     return f(false);
//   })
//   .then(() => {
//     console.log('我永远不会被输出');//该then方法中没有第二个回调,所以不会对错误进行处理
//   })
//   .then(() => {

//   })
//   .catch(e => {
//     console.log(e);
//     return f(false) ;//这个错误处理没有进行处理,页面会报错处理,这个问题ES文档没有详细说明,不过有不少库可以处理。
//   });

//----------------------------------------
// finally
// 不论成功还是失败 finally中的内容一定会执行,可以用来进行收尾工作

f(true)
  .then(data => {
    console.log(data);
    return f(false);
  })
  .catch(e => {
    console.log(e);
    return f(false);
  })
  .finally(() => {
    console.log(100);
  });

6. 浅谈Promise三种状态

7.感受下Promise.all()方法,主要用于管理多个函数的执行状态

在以前,我们如果要管理多个函数,并且要统计函数的执行情况是要按下面这样

//不是用Promise.all
let count = 0;用于统计四个方法都结束了
let err = false;

function func() {
  if (count < 4) return;

  if (err) {
    // ....
  }

  console.log('全部拿到了 !');
}

function getData1() {
  setTimeout(() => {
    console.log('第一条数据加载成功');
    count ++;
    func();
  }, 1000);
}

function getData2() {
  setTimeout(() => {
    console.log('第二条数据加载成功');
    count ++;
    func();
  }, 1000);
}

function getData3() {
  setTimeout(() => {
    console.log('第三条数据加载成功');
    count ++;
    func();
  }, 1000);
}

function getData4() {
  setTimeout(() => {
    console.log('第四条数据加载成功');
    count ++;
    func();
  }, 1000);
}

getData1();
getData2();
getData3();
getData4();

为了解决这个状况,我们可以使用Promise.all方法。all()中如果参数是空数组就默认为正确状况,出现正确或错误的Promise状况都会返回到数组中。

// Promise.all方法可以把多个promise实例 包装成一个新的promise实例
// Promise.all([ promise1, promise2 ]) : Promise

// 模拟需要多个请求的数据 才能进行下一步操作的情况

function getData1() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('第一条数据加载成功');
      resolve('data1');
    }, 1000);
  });
}

function getData2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('第二条数据加载成功');
      resolve('data2');
    }, 1000);
  });
}

function getData3() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('第三条数据加载成功');
      resolve('data3');
    }, 1000);
  });
}

function getData4() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // console.log('第四条数据加载成功');
      reject('data4 err');
    }, 500);
  });
}

let p = Promise.all([]);

p.then(arr => {
  console.log(arr);
}, e => {
  console.log(e);
});

8.感受下Promise.race()方法,主要用于管理多个函数的竞赛状态(用于一个请求有响应了,马上去执行下一步的程序)。

一旦有一个Promise决议为成功或者失败,就会立马把Promise的值传递过去使实例的状态改变。race()参数为空数组是会处于挂载状态。

// 不使用pormise.race

let flag = false;
function func(data) {
  if (flag) return;
  flag = true;

  console.log(data);
}

function getData1() {
  setTimeout(() => {
    console.log('第一条数据加载成功');
    func({name: 'xiaoming'});
  }, 500);
}

function getData2() {
  setTimeout(() => {
    console.log('第二条数据加载成功');
    func({name: 'xiaohong'});
  }, 600);
}

getData1();
getData2();

// Promise.race([ promise1, promise2 ]) : Promise

// function getData1() {
//   return new Promise((resolve, reject) => {
//     setTimeout(() => {
//       console.log('第一条数据加载成功');
//       reject('err');
//     }, 500);
//   });
// }

// function getData2() {
//   return new Promise((resolve, reject) => {
//     setTimeout(() => {
//       console.log('第二条数据加载成功');
//       resolve('data2');
//     }, 1000);
//   });
// }

// function getData3() {
//   return new Promise((resolve, reject) => {
//     setTimeout(() => {
//       console.log('第三条数据加载成功');
//       resolve('data3');
//     }, 1000);
//   });
// }

// let p = Promise.race([getData1(),getData2(),getData3()]);

// p.then(data => {
// 	console.log(data);
// }, e => {
// 	console.log(e);
// })

9.同步任务转为异步任务

一般事件执行情况下,同步任务会比异步任务先执行。所以可以通过Promise.resolve的性质进行转化。

//注释代码体现了异步与同步的执行
// console.log(1);

// let p = new Promise(resolve => {
//   console.log(2);
//   resolve();
//   console.log(3);
// });

// console.log(4);

// p.then(() => {
//   console.log(5);
// });

// console.log(6);


// 把同步的任务转成异步任务

function createAsyncTask(syncTask) {
  return Promise.resolve(syncTask).then(syncTask => syncTask());
}

createAsyncTask(() => {
  console.log('我变成了异步任务!!!');
  return 1 + 1;
}).then(res => {
  console.log(res);
});

console.log('我是同步任务!');
发布了34 篇原创文章 · 获赞 0 · 访问量 709

猜你喜欢

转载自blog.csdn.net/qq_18547381/article/details/104160668