JS异步进化与Promise

JavaScript 是单线程的,但它并不是无法处理异步操作。相反,JavaScript 的单线程特性和其事件循环机制使得它在处理异步任务方面非常高效

回调函数(Callback Functions)

一开始JS使用回调的形式来处理异步的结果,但是异步的弊端很大

例如:无法更好的处理错误,无法追溯数据来源,无法使用同步,回调地狱等问题

javascript 复制代码
console.log("开始");

setTimeout(() => {
  console.log("异步操作完成");
}, 1000);

console.log("结束");

//result

开始
结束
异步操作完成

回调地狱是最头疼的,所以就需要改变他

javascript 复制代码
setTimeout(() => {
    console.log("第一步完成");
    setTimeout(() => {
        console.log("第二步完成");
        setTimeout(() => {
            console.log("第三步完成");
        }, 1000);
    }, 1000);
}, 1000);

Promise(Promise A+ 规范)

所谓Promise 就是一个承诺

Promise的状态

  • Pending**(待定)**: 初始状态,既不是成功也不是失败
  • resolved**/** fullfilled**(已完成)**: 表示操作成功完成
  • Rejected**(已失败)**: 表示操作失败
javascript 复制代码
//初始状态
let promise = new Promise((resolve, reject) => {
  // promise 初始状态是 pending
});


//Fulfilled
let promise = new Promise((resolve, reject) => {
  resolve('成功的结果');
});

promise.then((value) => {
  console.log(value); // 输出: 成功的结果
});


//Rejected
let promise = new Promise((resolve, reject) => {
  reject('失败的原因');
});

promise.catch((reason) => {
  console.log(reason); // 输出: 失败的原因
});

切记你从一个状态改变到另一个状态后就无法再改变了

Promise的存储

Promise 的状态可以从 pending 变为 fulfilledrejected,但一旦变为 fulfilledrejected,就不能再变为其他状态。这种状态的不可变性确保了 Promise 的一致性和可靠性,每一种状态都会有定义的返回的值

当执行函数调用 resolve 时,Promise 的状态从 pending 变为 fulfilled

resolve 可以接受一个参数,作为 Promise 成功的值, PromiseResult变为存储的数据 , 调用then的第一个回调函数来返回数据

javascript 复制代码
let promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功的结果');
  }, 1000);
});

promise.then((value) => {
  console.log(value); // 1秒后输出: 成功的结果
});

当执行函数调用 reject 时,Promise 的状态从 pending 变为 rejected

reject 可以接受一个参数,作为 Promise 失败的原因, PromiseResult变为存储的数据 或 异常对象

javascript 复制代码
let promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('失败的原因');
  }, 1000);
});

promise.catch((reason) => {
  console.log(reason); // 1秒后输出: 失败的原因
});

Promise实例方法

.then

  • 用于指定当 Promise 成功时的回调函数
  • 它接受两个参数,第一个是成功时的回调函数onFulfilled
  • 第二个是失败时的回调函数onRejected(可选)
  • 返回一个新的 Promise 对象
javascript 复制代码
const p1 = new Promise((resolve, reject) => {
  resolve("成功!");
  // 或
  // reject(new Error("错误!"));
});

p1.then(
  (value) => {
    console.log(value); // 成功!
  },
  (reason) => {
    console.error(reason); // 错误! //但是这个回调不常用,建议使用.catch
  },
);

.catch

  • 用于指定当 Promise 失败时的回调函数onRejected
  • 抛出错误也可以使状态变为Rejected
  • Promise已对现,则catch不会被调用
  • 返回一个新的 Promise 对象
javascript 复制代码
let promise = new Promise((resolve, reject) => {
  reject('失败');
});

promise.catch(function(reason) {
  console.log(reason); // 失败
});

.finally

  • 用于指定不论 Promise 最终状态如何都会执行的回调函数
  • 返回一个新的 Promise 对象
javascript 复制代码
function checkMail() {
  return new Promise((resolve, reject) => {
    if (Math.random() > 0.5) {
      resolve('Mail has arrived');
    } else {
      reject(new Error('Failed to arrive'));
    }
  });
}

checkMail()
  .then((mail) => {
    console.log(mail);
  })
  .catch((err) => {
    console.error(err);
  })
  .finally(() => {
    console.log('Experiment completed');
  });

Promise静态方法

.resolve

  • 返回一个成功的以给定值解析后的 Promise****对象
  • 如果传入的参数是一个 Promise 对象,则参数的结果直接影响返回值
  • 如果不是 Promise****对象,那么就直接返会成功的 Promise****对象
  • 该函数将嵌套的类 Promise****对象(例如,一个将被兑现为另一个 Promise****对象的 Promise****对象)展平,转化为单个 Promise****对象,其兑现值为一个非 thenable****值
javascript 复制代码
Promise.resolve(42).then(function(value) {
  console.log(value); // 42 //resolve
});

let p1 = Promise.resolve(521);
console.log(p1)  //resolve

.reject

  • 返回一个失败的 Promise
  • 无论参数的形式,结果都是失败的,哪怕是成功的Promise
javascript 复制代码
function resolved(result) {
  console.log('Resolved');
}

function rejected(result) {
  console.error(result);
}

Promise.reject(new Error('fail')).then(resolved, rejected);
// Expected output: Error: fail

.all

  • 接受一个包含多个 Promise 的数组,返回的也是数组
  • 返回一个新的 Promise**, 当所有传入的** Promise****都成功完成( fulfilled**)时完成**
  • 或者只要有一个 Promise****失败( rejected**)时就失败并带有第一个被拒绝的原因**
javascript 复制代码
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// Expected output: Array [3, 42, "foo"]

.race

  • 接受一个包含多个 Promise 的数组
  • 返回一个新的 Promise**,谁先执行完毕,谁的结果就决定** race****的结果
javascript 复制代码
const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);
  // Both resolve, but promise2 is faster
});
// Expected output: "two"

.any

  • 接受一个可迭代对象
  • 返回一个新的 Promise只要传入的 Promise****中有一个成功,并返回第一个兑现的值
  • 如果所有的 Promise 都失败,则返回一个失败的 Promise,并附带一AggregateError 错误
javascript 复制代码
const promise1 = Promise.reject(0);
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'quick'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'slow'));

const promises = [promise1, promise2, promise3];

Promise.any(promises).then((value) => console.log(value));

// Expected output: "quick"

关于Promise的详细内容还有许多,本文仅做简略描述,请谅解

async与await (ES8/ES2017)

他的作用就是使你的promise代码看起来像同步一样

async

  • 用于声明一个异步函数
  • 异步函数默认返回一个 Promise 对象
  • 如果函数内部返回的是一个非 Promise 的值,它会被自动封装成 Promise.resolve(value)

await

  • 用于等待一个异步操作(即 Promise)的完成
  • await 必须在 async 函数内部使用
  • 它会暂停代码执行,直到 Promise 的结果返回(成功或失败)

传统写法

javascript 复制代码
function fetchData() {
    return new Promise((resolve) => {
        setTimeout(() => resolve("数据加载完成"), 1000);
    });
}

fetchData()
    .then((result) => {
        console.log(result);
        return "下一步操作";
    })
    .then((nextResult) => {
        console.log(nextResult);
    })
    .catch((err) => {
        console.error(err);
    });

新式写法

javascript 复制代码
async function fetchData() {
    return new Promise((resolve) => {
        setTimeout(() => resolve("数据加载完成"), 1000);
    });
}

async function run() {
    try {
        const result = await fetchData();
        console.log(result);

        const nextResult = "下一步操作";
        console.log(nextResult);
    } catch (err) {
        console.error(err);
    }
}

run();
相关推荐
秋沐2 分钟前
微前端-MicroApp
前端·react.js·webpack·前端框架·npm
Jiaberrr6 分钟前
打造双层环形图:基础与高级渐变效果的应用
前端·javascript·vue.js·信息可视化·echarts
GISer_Jing30 分钟前
React前端面试题详解(一)
前端·react.js·前端框架
呵呵哒( ̄▽ ̄)"30 分钟前
React 实战选择互动特效小功能
前端·javascript·react.js
Python私教35 分钟前
Docker化部署Django:高效、可扩展的Web应用部署策略
前端·docker·django
YiSLWLL38 分钟前
Django+Nginx+uwsgi网站Channels+redis+daphne多人在线聊天实现粘贴上传图片
javascript·python·nginx·django
查拉图斯特拉面条1 小时前
前端页面元素定位与XPath优化
前端·ui·自动化
大今野1 小时前
JavaScript的let、var、const
开发语言·javascript·ecmascript
刺客-Andy1 小时前
React第十节组件之间传值之context
前端·javascript·react.js
顾北川_野1 小时前
Android 12.0 通知--PendingIntent基本代码
java·前端·javascript