解读Es6之 promise
单线程: 在同一时间只能有同一任务进行。JavaScript就是一门单线程语言
当有多个任务需要进行时,则需要进行排队,前一个执行完毕才能执行下一个;
当前一个任务报错后,则不进行下一个
案例如下:
// 1、同步 function fun1(){ console.log(1) // throw Error("121212") // 错误时,则不向后进行 } function fun2(){ console.log(2) } function fun3(){ console.log(3) } // fun1() // fun2() // fun3() /* 正确时输出 1 2 3 错误时输出 解读promise.html:23 Uncaught Error: 121212 at fun1 (解读promise.html:23) at 解读promise.html:31 */
/* 为什么要使用单线程语言? js是被设计在浏览器中使用的,浏览器多用于数据等的展示、更改等。 若有多个线程同时进行,如: 数据1: “嘿嘿嘿,我是页面上的数据1,我的真实名字叫山本,我就是这么自信的数据” (页面数据) 线程1: “二营长,你tm的意大利炮,给我干山本一炮” (对数据删除操作) 线程2: “二营长,活捉山本”(对数据进行修改) 浏览器:“身为二营长的我,太南了” (浏览器不知执行哪歩操作) 这样,浏览器就会一脸闷逼。 所以,js被设计为单线程,即可给山本一炮,干不死,再活捉! (最近独立团看多了,哈哈,简单比喻下吧) */
/* 异步:即同时进行,当某个任务存在ajax等异步操作时,不必执行完才会执行下一个,如下 */
// 2、异步 function fun4(){ console.log(4) } function fun5(){ setTimeout(()=>{ console.log(5) },0) } function fun6(){ console.log(6) } // fun4() // fun5() // fun6() /* 输出 4 6 5 */
/*
异步编程,
1、使用回调函数
2、使用es6的promise ( 重点讲解 )
*/
// Promise /* 1、检查当前浏览器是否支持promise typeof(Promise)==="function" 2、三种状态 pending(进行中)、fulfilled(已成功)和rejected(已失败) 3、可以使异步操作变同步 */ /* 基本使用: 参数为js引擎自带 resolve : 将pending状态转为 fulfilled状态 reject : 将pending状态转为 rejected状态 */
let Promise_demo1 = new Promise((resolve, reject) => { let num = Math.floor( Math.random() * 10 ) if (num > 5) { // 正确时 执行这个,并将参数传递出去 resolve(num) } else { // 错误时,执行这个,可以支持任意参数 reject(num + '错误了!') } }) Promise_demo1 .then( (data) => { // 表示 为成功状态时,要执行的,即通过 resolve 后执行 // console.log(data) }) .catch( (Error) => { // 表示 为失败状态时,要执行的,即通过 reject 后执行 // console.log(Error) }) // 以上通过 then catch ,也可只在then中执行,一个参数为成功时执行,第二个参数为失败时执行 // Promise_demo1 // .then( (data) => { // console.log(data) // }, (err) => { // console.log(err) // } ) // 通过函数使用promise function timeout(_time){ let num = Math.floor( Math.random() * 10 ) return new Promise( (resolve, reject) => { setTimeout(()=>{ resolve(num) },_time) } ) } timeout(1000) .then( (data) => { // console.log(data) // 依次在1秒输出随机数 } ) .catch( (err) => {} ) /* 小插曲: Uncaught (in promise) 期间,若报这个错,即reject发出错误, 1、需要使用catch接收,即添加 .catch((e) => {}) 2、或,不使用reject返回错误 为了严谨,推荐使用第一种 */ /* 当既有promise执行,又有其他同步操作执行 先 执行promise 再 执行同步操作 后 执行promise.then 后 执行异步操作 案例如下: */ let Promise_demo2 = new Promise( (resolve, reject) => { // console.log("promise内支持的") resolve('promise成功后执行的') } ) Promise_demo2 .then( (data) => { // console.log(data) } ) function func7(){ // console.log('同步操作') } function func8(){ setTimeout( ()=>{ console.log("异步操作") },0 ) } // func7() // func8() /* 输出 promise内支持的 同步操作 promise成功后执行的 异步操作 */ /* resolve, reject 不仅可以返回一个参数,还可以返回一个promise 情况一: 参数的promise 的请求时间小于 调用者的promise请求时间 以下输出: 1秒后:Uncaught (in promise) 2121 ( 即先执行 .catch ) 3秒后:2121 因为p1作为参数,在1秒后执行,p2在3秒后将p1作为参数传出去再执行 */ const p1 = new Promise(function (resolve, reject) { // setTimeout(() => reject('2121'), 1000) }) const p2 = new Promise(function (resolve, reject) { // setTimeout(() => resolve(p1), 3000) }) p2 .then(result => console.log(result)) .catch(error => console.log(error)) /* 情况二: 参数的promise 的请求时间 大于 调用者的promise请求时间 以下输出: 3秒后 Error: 错误了 因为p4在1秒后状态改变,resolve返回的又是新的promise,导致p4的状态失效,p3的状态替换了p4的状态 */ const p3 = new Promise(function (resolve, reject) { // setTimeout(() => reject(new Error('错误了')), 3000) }) const p4 = new Promise(function (resolve, reject) { // setTimeout(() => resolve(p3), 1000) }) p4 .then(result => console.log(result)) .catch(error => console.log(error)) /* .finally 不管是成功还是失败后,都会执行 */ let Promise_demo3 = new Promise( (resolve, reject) => { let num = Math.floor( Math.random() * 10 ) if( num > 5 ) { // resolve('Oh Yeah') } else { // reject('Oh No') } } ) Promise_demo3 .then( data => console.log(data) ) .catch( data => console.log(data) ) .finally( () => console.log("I am finally") ) // 都会执行 /* Promise.all() 用于将多个Promise实例,包装成一个promise实例 如 let p_all = Promise.all( [ promise1, promise2, promise3 ] ); 当所有参数返回resolve时, promise.all则返回resolve 当有一个参数返回reject时,promise.all则返回reject 如下: */ let arrImg = ['img/0.jpg', 'img/1.jpg', 'img/2.jpg']; function loadImg(url){ return new Promise( (resolve, reject) => { let img = new Image(); // img.src = url; // img.onload = () => resolve(img); // 或 resolve(this) // img.onerror = () => reject('加载失败'); } ) } let PromiseAll = Promise.all( [ loadImg(arrImg[0]), loadImg(arrImg[1]), loadImg(arrImg[2]) ] ) // 若将其中的一个改为不存在的路径时,则会报错 如将loadImg(arrImg[0])改为 loadImg(arrImg[3]), PromiseAll .then( images => { // images.forEach(value => document.body.appendChild(value)) } ) .catch( data => console.log(data,'错误时提示') ) .finally( () => console.log('程序运行完成') ) /* Promise.race() 参数均为promise const p = Promise.race([p1, p2, p3]); 当其中一个参数的状态改变时,p的状态就会改变 */ /* Es2020 新加 Promise.allSettled() const p_allSe = Promise.allSettled([p1, p2, p3]); 可能部分浏览器暂时不支持, 使用场景:不关心异步操作的结果,只关心这些操作有没有结束 */ // let p_allSe = Promise.allSettled([p3, p4]) // p_allSe.then( result => console.log( result ) ) /* Promise.resolve() 将现有对象转为 Promise 对象 不知实际项目中能解决什么问题,有大神知道的可以回复下 */ /* Promise.reject() */ // let p_reject = Promise.reject(new Error('12121')) // p_reject.catch((err)=> console.log(err)) // 报出错误来 /* Promise.try() */ // 将两个或多个含有异步操作的函数 同步执行 function func9(){ return new Promise( resolve => { setTimeout(() => { console.log(9) resolve() },1000) } ) } function func10(){ console.log(10) } func9().then( ()=>func10() ) // function func9(){ setTimeout(() => { console.log(9) },1000) } function func10(){ console.log(10) }