(五)ES6 异步编程

文章目录

    • 一、Promise 对象
        • 1. 认识 Promise
          • (1) Promise 是什么
          • (2) 基本用法
          • (3) then 方法
          • (4) resolve 和 reject 函数的参数
        • 2. Promise 的实例方法
          • (1) then()
          • (2) catch()
          • (3) finally()
        • 3. Promise 的构造函数方法
          • (1) Promise.resolve()
          • (2) Promise.reject()
          • (3) Promise.all()
          • (4) Promise.race()
          • (5) Promise.allSettled()
        • 4. Promise 的注意事项和应用
          • (1) 注意事项
          • (2) 应用
    • 二、Generator 函数
    • 三、async 函数

一、Promise 对象

1. 认识 Promise

(1) Promise 是什么
  • Promise 是异步操作的一种解决方案
  • Promise 一般用来解决层层嵌套的回调函数(回调地狱 callback hell)的问题
(2) 基本用法
  • 实例化构造函数生成实例对象
    Promise 解决的不是回调函数,而是回调地狱
    const p = new Promise(() => {});
  • Promise 的状态:
    • Promise 有 3 种状态,一开始是 pending(未完成)
    • 执行 resolve,变成 fulfilled (resolved),已成功
    • 执行 reject,变成 rejected,已失败
    • Promise 的状态一旦变化,就不会再改变了
const p = new Promise((resolve, reject) => {
	// pending->fulfilled
	resolve();
	// pending->rejected
	reject();
});
(3) then 方法
p.then(
	() => {
		console.log('success');
	},
	() => {
		console.log('error');
	}
);
(4) resolve 和 reject 函数的参数
const p = new Promise((resolve, reject) => {
	// resolve('succ');
	// 也可以传一些数据
	resolve({ username: 'mike' });

	reject('reason');
	// 比较常用的是传一个错误对象
	reject(new Error('reason'));
});
p.then(
	// 在 then 方法中接收数据
	data => {
		console.log('success', data);	//success {username: "mike"}
	},
	err => {
		console.log('error', err);	// error reason
	}
);

2. Promise 的实例方法

(1) then()
  • 什么时候执行:
    • pending —> fulfilled 时,执行 then 的第一个回调函数
    • pending —> rejected 时,执行 then 的第二个回调函数
    • 状态不改变,then() 的回调函数都不会被执行
  • 执行后的返回值:
    then 方法执行后返回一个新的 Promise 对象
const p = new Promise((resolve, reject) => {
	resolve();
	// reject();
});
const p2 = p
	.then(
		() => {},
		() => {}
	)
	.then()
	.then();
  • then 方法返回的 Promise 对象的状态改变
const p = new Promise((resolve, reject) => {
	resolve();
	// reject();
});
p.then(
	() => {
		console.log('success');
	},
	() => {
		console.log('err');

		// 在 then 的回调函数中,return 后面的东西,会用 Promise 包装一下
		// return undefined;
		// 等价于
		// return new Promise(resolve => {
		//   resolve(undefined);
		// });

		// return 123;
		// 等价于
		// return new Promise(resolve => {
		//   resolve(123);
		// });

	// 默认返回的永远都是成功状态的 Promise 对象
		// 主动设置为失败
		// return new Promise((resolve, reject) => {
		//   reject('reason');
		// });
	}
)
.then(
	data => {
		console.log('success2', data);

		// return undefined;
		// 默认
		return new Promise(resolve => {
			resolve(undefined);
		});
	},
	err => {
		console.log('err2', err);
	}
)
.then(
	data => {
		console.log('success3', data);
	},
	err => {
		console.log('err3', err);
	}
);
(2) catch()
  • catch 的作用:
then(
	data => {},
	err => {}
);
// 一般只写第一个回调用来处理成功的...
then(data => {});
// 可以理解为用 then 专门处理成功

所以用 catch 专门用来处理 rejected 状态
catch 本质上是 then 的特例 then(null, err => {});

  • 基本用法:
new Promise((resolve, reject) => {
	resolve(123);
	reject('reason');
})
	.then(data => {
		console.log(data);
	})
	// .then(null, err => {
	// 	console.log(err);
	// });
	.catch(err => {
		console.log(err);

 		// return undefined;
		throw new Error('reason');
	})
	.then(data => {
		console.log(data);
	})
	.catch(err => {
		console.log(err);
	});

// catch() 可以捕获它前面的错误
// 一般总是建议,Promise 对象后面要跟 catch 方法,这样可以处理 Promise 内部发生的错误
(3) finally()
  • 什么时候执行:
    当 Promise 状态发生变化时,不论如何变化都会执行,不变化不执行
  • 本质:
    finally() 本质上是 then() 的特例
new Promise((resolve, reject) => {
	// resolve(123);
	reject('reason');
})
	.finally(data => {
		console.log(data);
	})
	.catch(err => {});

等同于

new Promise((resolve, reject) => {
	// resolve(123);
	reject('reason');
})
	.then(
		result => {
			return result;
		},
		err => {
			return new Promise((resolve, reject) => {
				reject(err);
			});
		}
	)
	.then(data => {
		console.log(data);
	})
	.catch(err => {
		console.log(err);
	});

3. Promise 的构造函数方法

(1) Promise.resolve()
  • 是成功状态 Promise 的一种简写形式
new Promise(resolve => resolve('foo'));
// 简写
Promise.resolve('foo');
  • 参数:

1)一般参数

Promise.resolve('foo').then(data => {
	console.log(data);
});

2)特殊参数:Promise 对象
当 Promise.resolve() 接收的是 Promise 对象时,直接返回这个 Promise 对象,什么都不做

const p1 = new Promise(resolve => {
	setTimeout(resolve, 1000, '我执行了');
	// 等价于
	// setTimeout(() => {
	//   resolve('我执行了');
	// }, 1000);
});
	
Promise.resolve(p1).then(data => {
	console.log(data);
});
// 等价于
// p1.then(data => {
// 	console.log(data);
// });
// console.log(Promise.resolve(p1) === p1);	// true

// 当 resolve 函数接收的是 Promise 对象时,后面的 then 会根据传递的 Promise 对象的状态变化决定执行哪一个回调
new Promise(resolve => resolve(p1)).then(data => {
	console.log(data);
});

3)具有 then 方法的对象
当参数是具有 then 方法的对象时,会立即执行它的 then 方法

const thenable = {
	then(resolve, reject) {
		console.log('then');
		resolve('data');
		// reject('reason');
	}
};

Promise.resolve(thenable).then(
	data => console.log(data),
	err => console.log(err)
);

console.log(Promise.resolve(thenable));
(2) Promise.reject()
  • 失败状态 Promise 的一种简写形式
new Promise((resolve, reject) => {
	reject('reason');
});
// 简写
Promise.reject('reason');
  • 参数:

不管什么参数,都会原封不动地向后传递,作为后续方法的参数

// 以 Promise 对象为例
const p1 = new Promise(resolve => {
	setTimeout(resolve, 1000, '我执行了');
});
Promise.reject(p1).catch(err => console.log(err));

new Promise((resolve, rejcet) => {
	resolve(123);
})
	.then(data => {
		// return data;
		// return Promise.resolve(data);

		return Promise.reject('reason');
	})
	.then(data => {
		console.log(data);
	})
	.catch(err => console.log(err));
(3) Promise.all()
  • 作用:
    Promise.all() 关注多个 Promise 对象的状态变化
    传入多个 Promise 实例,包装成一个新的 Promise 实例返回
  • 基本用法:
    Promise.all() 的状态变化与所有传入的 Promise 实例对象状态有关
    所有状态都变成 resolved,最终的状态才会变成 resolved
    只要有一个变成 rejected,最终的状态就变成 rejected
const delay = ms => {
	return new Promise(resolve => {
		setTimeout(resolve, ms);
	});
};

const p1 = delay(1000).then(() => {
	console.log('p1 完成了');

	// return 'p1';
	return Promise.reject('reason');
});
const p2 = delay(2000).then(() => {
	console.log('p2 完成了');

	return 'p2';
	// return Promise.reject('reason');
});

const p = Promise.all([p1, p2]);
p.then(
	data => {
		console.log(data);
	},
	err => {
		console.log(err);
	}
);
(4) Promise.race()
  • 基本用法:
    Promise.race() 的状态取决于第一个完成的 Promise 实例对象,如果第一个完成的成功了,那最终的就成功;如果第一个完成的失败了,那最终的就失败
const delay = ms => {
	return new Promise(resolve => {
		setTimeout(resolve, ms);
	});
};
const p1 = delay(1000).then(() => {
	console.log('p1 完成了');

	return 'p1';
	// return Promise.reject('reason');
});
const p2 = delay(2000).then(() => {
	console.log('p2 完成了');

	// return 'p2';
	return Promise.reject('reason');
});

const racePromise = Promise.race([p1, p2]);
racePromise.then(
	data => {
		console.log(data);
	},
	err => {
		console.log(err);
	}
);
(5) Promise.allSettled()
  • 基本用法:
    Promise.allSettled() 的状态与传入的Promise 状态无关,永远都是成功的
    它只会忠实的记录下各个 Promise 的表现
const delay = ms => {
	return new Promise(resolve => {
		setTimeout(resolve, ms);
	});
};
const p1 = delay(1000).then(() => {
	console.log('p1 完成了');

	return 'p1';
	// return Promise.reject('reason');
});
const p2 = delay(2000).then(() => {
	console.log('p2 完成了');

	// return 'p2';
	return Promise.reject('reason');
});

const allSettledPromise = Promise.allSettled([p1, p2]);
allSettledPromise.then(data => {
	console.log('succ', data);
});

4. Promise 的注意事项和应用

(1) 注意事项
  • resolve 或 reject 函数执行后的代码
    推荐在调用 resolve 或 reject 函数的时候加上 return,不再执行它们后面的代码
new Promise((resolve, reject) => {
	// return resolve(123);
	return reject('reason');

	console.log('hi');
});
  • Promise.all / race / allSettled 的参数问题
    参数如果不是 Promise 数组,会将不是 Promise 的数组元素转变成 Promise 对象
Promise.all([1, 2, 3]).then(datas => {
	console.log(datas);
});
// 等价于
Promise.all([
	Promise.resolve(1),
	Promise.resolve(2),
	Promise.resolve(3)
]).then(datas => {
	console.log(datas);
});

不只是数组,任何可遍历的都可以作为参数
数组、字符串、Set、Map、NodeList、arguments

// 以 Set 为例
Promise.all(new Set([1, 2, 3])).then(datas => {
	console.log(datas);
});
  • Promise.all / race / allSettled 的错误处理
    错误既可以单独处理,也可以统一处理
    一旦被处理,就不会在其他地方再处理一遍
const delay = ms => {
	return new Promise(resolve => {
		setTimeout(resolve, ms);
	});
};

const p1 = delay(1000).then(() => {
	console.log('p1 完成了');

	// return 'p1';
	return Promise.reject('reason');
});
// 	.catch(err => {
//  	 console.log('p1', err);
// 	});
const p2 = delay(2000).then(() => {
	console.log('p2 完成了');

	return 'p2';
	// return Promise.reject('reason');
});
// 	.catch(err => {
//   	console.log('p2', err);
// 	});

const allPromise = Promise.all([p1, p2]);
allPromise
	.then(datas => {
		console.log(datas);
	})
	.catch(err => console.log(err));
(2) 应用

异步加载图片

<body>
    <img
      src="https://img.mukewang.com/5e6af63d00011da318720764.jpg"
      alt=""
      id="img"
    />

    <script>
      // 异步加载图片
      const loadImgAsync = url => {
        return new Promise((resolve, reject) => {
          const img = new Image();

          img.onload = () => {
            resolve(img);
          };

          img.onerror = () => {
            reject(new Error(`Could not load image at ${url}`));
          };

          img.src = url;
        });
      };

      const imgDOM = document.getElementById('img');
      loadImgAsync('https://2img.mukewang.com/5f057a6a0001f4f918720764.jpg')
        .then(img => {
          console.log(img.src);
          setTimeout(() => {
            imgDOM.src = img.src;
          }, 1000);
        })
        .catch(err => {
          console.log(err);
        });
    script>
body>

二、Generator 函数

三、async 函数

你可能感兴趣的:(前端学习:ES6与Ajax,前端,es6,javascript)