前端手写题

79 阅读4分钟

1. 基本概念

在 JavaScript 里,异步操作十分常见,像网络请求、文件读取等。以往,处理异步操作通常采用回调函数的方式,但这种方式在处理多个异步操作嵌套时,会让代码变得复杂难读,也就是所谓的 “回调地狱”。Promise 正是为解决这一问题而出现的。

Promise 代表一个异步操作的最终完成或者失败,并且返回其结果。它有三种状态:

  • pending(进行中) :初始状态,既不是成功,也不是失败状态。

  • fulfilled(已成功) :意味着操作成功完成。

  • rejected(已失败) :表示操作失败。

Promise 的状态一旦从 pending 变为 fulfilled 或者 rejected,就不会再改变。

2. 创建 Promise

Promise构造函数 创建一个 Promise 实例需要传入一个执行器函数(executor),这个执行器函数接收两个参数:resolve 和 reject,它们都是函数。
executor函数:执行器 (resolve,reject)=>{}
executor会在Promise内部立即同步调用。异步操作在执行器中执行

3. 处理 Promise 结果

使用 then 方法处理 Promise 成功的结果,使用 catch 方法处理 Promise 失败的结果。

4. Promise 的链式调用

javascript

function asyncOperation1() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve('操作 1 完成');
        }, 1000);
    });
}

function asyncOperation2(result) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(result + ',操作 2 完成');
        }, 1000);
    });
}

asyncOperation1()
  .then(asyncOperation2)
  .then((finalResult) => {
        console.log(finalResult); // 输出:操作 1 完成,操作 2 完成
    })
  .catch((error) => {
        console.error(error);
    });

在这个例子中,asyncOperation1 和 asyncOperation2 都是返回 Promise 实例的异步函数。通过 then 方法将它们链式调用,实现了按顺序执行异步操作。

5. 静态方法

  • Promise.all:接收一个 Promise 数组,当所有 Promise 都成功时,返回一个新的 Promise,其结果是一个包含所有 Promise 结果的数组;只要有一个 Promise 失败,就会立即返回一个失败的 Promise
  • Promise.race:接收一个 Promise 数组,只要其中一个 Promise 状态改变(成功或失败),就会返回这个 Promise 的结果。
  • 总结

Promise 是 JavaScript 中处理异步操作的强大工具,它通过状态管理和链式调用,让异步代码的编写和维护更加简单和清晰。同时,Promise 的静态方法也提供了处理多个异步操作的便捷方式。

Promise手写题

手写 Promise

class Promise{        //类
 constructor (executor){
 this.status='pending'
 this.value=undefined     //成功的结果
 this.reason=undefined    //失败的原因
 
 //存放成功的回调 
 this.onResolvedCallbacks = []; 
 //存放失败的回调 
 this.onRejectedCallbacks = [];
 }
 
 //resolve 函数
 let resolve=(value)=>{
 if(this.status === 'pending')
 { this.value = value; 
   this.status = "resolved"; 
   this.onResolvedCallbacks.forEach(fn => fn()); } }// 执行所有成功的回调函数
   
    //reject 函数
 let reject=(reason)=>{
 if(this.status==='pending'){
 this.reason=reason
 this.status='pengding'
 this.onRejectedCallbacks.forEach(fn=>fn() // 执行所有失败的回调函数
 }
 
 //考虑到异常情况
 
 try{
 executor(resolve,reject)  //executor 函数立即执行
 }catch(e){
 reject(e)}  // 如果 executor 函数抛出异常,调用 reject 方法
    }
 }

手写 Promise.all

Promise.all=function(promises)//传入一个数组{
return new Promise((resolve,reject)=>{
let count=0    //计数器
let result=[]  //保存结果的数组
for(let i=0;i<promises.length){
promises[i].then(v=>{
count++
result[i]=v  //将每一个promise的结果存入数组中
if(count===promises.length){resolve (result)}  //判断是否都执行完毕,将结果resolve
},r=>{
reject(r)
}

v 和 r 都是then 回调函数里面的

手写 Promise.race

Promise.race=function(promises){
    return new Promise((resolve,reject)=>{
        for(let i=0;i<promises.length){
           promises[i].then(v=>{ resolve(v)}, //只要有一个promise成功/失败,就立马返回结果
            r=>{reject(r) })
}
})

手写 Promise 封装 ajax请求

function sendAjax(url){
return new Promise((resolve,reject)=>{
const xhr=new XMLHttpRequest()  //创建对象
xhr.open('get',url)  //初始化
xhr.send()   //发送请求
//处理响应结果
xhr.onreadystatechange=function(){
if(xhr.readyState===4){
  //判断成功
  if(xhr.status>=200&&xhr.status<300){
  //成功执行
  resolve(xhr.response)  //响应体
  }else{ 
  //失败执行
  reject(xhr.status)}  //状态码
}
}

})
}

参考资料

promise.resolve()方法
传入的参数是非Promise 类型的对象,返回的结果是 成功的promise对象
传入的参数是Promise对象,则参数的结果 决定了resolve的结果

image.png

image.png

image.png

image.png

image.png

image.png

image.png

执行结果:success undefined
过程是 第一个 then 返回的是新的promise对象,返回的success 所以可以调用第二个 then 方法 打印success 但是第二个then 没有返回结果 所以返回的是一个成功的promise,成功的值没有定义 所以第三个then是undefined
原理:then的返回结果也是promise