Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
异步编程 主要指的是IO的代码(文件IO,数据库IO,网络请求)。解决方案:解决回调地狱问题。
创造了一个Promise实例
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。这两个函数都是可选的,不一定要提供。它们都接受Promise对象传出的值作为参数。
eg. 1-Promise基本语法.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise基本语法title>
head>
<body>
<script>
//实例化 Promise 对象
const p = new Promise(function(resolve, reject){
// 封装一个异步操作 这里用定时器做一个表示
setTimeout(function(){
// 得到一些数据
// let data = '数据库中的用户数据';
// 可以调用resolve, reject这两个函数来改变Promise对象的状态(初始化,成功,失败)
// resolve(data);
// 当调用完resolve函数,Promise对象状态就变成了成功,成功之后就可以调用promise 对象的 then 方法
let err = '数据读取失败';
// 如果失败,调用reject函数,调用完,Promise对象状态就变成了失败,调用then方法里面的第二个回调函数
reject(err);
}, 1000);
});
//调用 promise 对象的 then 方法
// then方法接收两个参数,两个都是函数类型的值,而且每一个函数都有一个形参,成功的一般叫value,失败的叫reason
p.then(function(value){
console.log(value);
}, function(reason){
console.error(reason);
})
script>
body>
html>
会用到nodejs里面的一些api,读取的是:resources文件夹里面的 为学.md
//1. 引入 fs 模块
const fs = require('fs');
// 2. 调用方法读取文件(没有使用promise)
// fs.readFile('./resources/为学.md', (err, data)=>{
// //如果失败, 则抛出错误
// if(err) throw err;
// //如果没有出错, 则输出内容
// console.log(data.toString());
// });
// 3. 使用 Promise 封装
const p = new Promise(function(resolve, reject){
fs.readFile("./resources/为学.mda", (err, data)=>{
//判断如果失败
if(err) reject(err);
//如果成功
resolve(data);
});
});
p.then(function(value){
console.log(value.toString());
}, function(reason){
console.log("读取失败!!");
});
操作显示:
上面代码中 2 调用方法读取文件 的方法代码少一些,但是一般都是用promise封装,因为单个任务看不出来效果,如果有多个异步任务,使用调用方法读取文件方法,代码就要不断缩减,使用promise封装,就不会持续缩进。
使用原生Ajax,向url发送请求
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<script>
// 使用原生Ajax,向url发送请求
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.apiopen.top/getJoke");
xhr.send();
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300 ) {
console.log(xhr.response);
}else {
console.error(xhr.status);
}
}
}
script>
body>
html>
接口失效,然后有点问题(代码没有问题),还未解决
使用Promise方式对这个进行个封装
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>发送 AJAX 请求title>
head>
<body>
<script>
// 接口地址: https://api.apiopen.top/getJoke
const p = new Promise((resolve, reject) => {
//1. 创建对象
const xhr = new XMLHttpRequest();
//2. 初始化
xhr.open("GET", "https://api.apiopen.top/getJ");
//3. 发送
xhr.send();
//4. 绑定事件, 处理响应结果
xhr.onreadystatechange = function () {
//判断
if (xhr.readyState === 4) {
//判断响应状态码 200-299
if (xhr.status >= 200 && xhr.status < 300) {
//表示成功
resolve(xhr.response);
} else {
//如果失败
reject(xhr.status);
}
}
}
})
//指定回调
p.then(function(value){
console.log(value);
}, function(reason){
console.error(reason);
});
script>
body>
html>
eg. Promise-then方法.js
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise.prototype.thentitle>
head>
<body>
<script>
//创建 promise 对象
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('用户数据');
// reject('出错啦');
}, 1000)
});
//调用 then 方法 then方法的返回结果是 Promise 对象, 对象状态由回调函数的执行结果决定
//1. 如果回调函数中返回的结果是 非 promise 类型的属性, 状态为成功, 返回值为对象的成功的值
// const result = p.then(value => {
// console.log(value);
// //1. 非 promise 类型的属性
// // return 'iloveyou';
// //2. 是 promise 对象
// // return new Promise((resolve, reject)=>{
// // // resolve('ok');
// // reject('error');
// // });
// //3. 抛出错误
// // throw new Error('出错啦!');
// throw '出错啦!';
// }, reason=>{
// console.warn(reason);
// });
//链式调用
// then 方法在指定回调可以只指定一个,可以不写失败
p.then(value=>{
}).then(value=>{
});
script>
body>
html>
回调执行特点
关于then返回的结果
返回结果是由回调函数的执行结果决定的。then返回结果是promise对象,对象状态由回调函数的执行结果决定
Promise一共有三种状态: 未决定的:pending 成功:resolved、fulfilled 失败:rejected
挨个读取文件夹里面的md文件
1 引用 fs 模块
//引入 fs 模块
const fs = require('fs');
fs.readFile('./resources/为学.md', (err,data1)=>{
fs.readFile('./resources/插秧诗.md', (err,data2)=>{
fs.readFile('./resources/观书有感.md', (err,data3)=>{
// 对上面三个文件做一个连接
let result = data1 + data2 + data3;
console.log(result);
});
});
});
实际项目一般不会这种写法,回调地狱。但有这种场景,比如数据库读取,先读取用户,才能有后续的读取内容
跟教学视频学习时老师的是直接 右键 run code 实现,但我的显示 undefined,这个问题没有解决。 然后换了个方式,打开终端,输入指令 node 6-Promise实践-读取多个文件.js,读取文件成功。
使用 promise 实现
// 引入 fs 模块
const fs = require("fs");
// fs.readFile('./resources/为学.md', (err, data1)=>{
// fs.readFile('./resources/插秧诗.md', (err, data2)=>{
// fs.readFile('./resources/观书有感.md', (err, data3)=>{
// let result = data1 + '\r\n' +data2 +'\r\n'+ data3;
// console.log(result);
// });
// });
// });
// 使用 promise 实现
const p = new Promise((resolve, reject) => {
fs.readFile("./resources/为学.md", (err, data) => {
resolve(data);
});
});
p.then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/插秧诗.md", (err, data) => {
resolve([value, data]);
});
});
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/观书有感.md", (err, data) => {
//压入
value.push(data);
resolve(value);
});
})
}).then(value => {
console.log(value.join('\r\n'));
});
如果出现buffer的情况
加一个toString()即可 (value. toString())
指定Promise对象失败的一个回调
eg. Promise-catch方法.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>catch方法title>
head>
<body>
<script>
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
//设置 p 对象的状态为失败, 并设置失败的值
reject("出错啦!");
}, 1000)
});
// p.then(function(value){}, function(reason){
// console.error(reason);
// });
p.catch(function(reason){
console.warn(reason);
});
script>
body>
html>
由then方法不指定第一个参数,结果就跟catch一样