深入浅出:JavaScript中 三大异步编程方案以及应用

1.前言

PromiseGeneratorasync/awaitJavascript异步编程的三个解决方案。废话不多说,进入正题。

2.概念

2.1 Promise概念

Promise是一个对象,代表了一个异步操作的最终完成(或者失败)的状态和结果值。它的状态有三个:pending(进行中)、fulfilled(已完成)、rejected(已失败),状态一旦确定就不可逆。Promise 支持链式调用,使用then方法,避免回调地狱。Promise的回调函数是异步执行,在同步代码执行完毕之后,微任务阶段进行执行。

2.2 Generator概念

Generator是 ES6引入的特殊函数,通过function*声明,使用yield暂停执行和next恢复函数执行,返回值是一个迭代器对象,通过迭代器对象控制函数的执行。

2.3 async/await概念

async/await是 ES2017引入的函数,是GeneratorPromise的语法糖,使得异步操作更加的方便。async声明函数,自动将函数返回值包装成Promsie对象。await可以配合 async使用,也可以单独使用(ES022为了解决模块异步的之间的加载问题)。暂停await的执行,等待 Promise的解决,并返回Promsie的值,等待的不是 Promise的值,则直接返回值。

⚠️:await 关键字后面的表达式的执行顺序先于async函数的暂停,换句话说await 右侧表达式的同步代码全部执行完毕,才会执行暂停逻辑。之后后面的代码块包装成一个微任务,放入微任务队列中。

3.使用场景

3.1 Promise使用场景

  • 很明确的成功或者失败的处理逻辑
  • 多个无任何关系的异步操作(Promise.all、Promise.any、Promise.allSettled、Promise.race)

3.2 Generator使用场景

  • 需要手动控制异步任务的执行
  • 复杂的迭代器场景
  • 状态机实现(多个状态的切换)

3.3 async/await使用场景

  • 使用同步代码串行执行异步逻辑

4.优缺点

4.1 Promise优缺点

  1. 优点:
  • 解决传统回调函数的回调地狱问题,为后面的 Generator 和 async/await 打下基础
  • 状态不可逆,更安全可靠
  • 具备统一的catch 方法捕捉错误
  1. 缺点:
  • 复杂流程的链式调用代码不直观
  • 状态不可逆,不能取消 Promise
  • 无法中途跳出链式调用,不能在使用break、continute、return 等控制语句

4.2 Generator优缺点

  1. 优点:
  • 对于异步任务操作更灵活,支持暂停/恢复异步流程
  1. 缺点:
  • 代码相对复杂,需要手动驱动控制器,学习成本高
  • 错误处理需要同时关注 try/catch 和外部的 throw,比较复杂

4.3 async/await优缺点

  1. 优点:
  • 代码简洁,可读性高
  • 错误处理可以使用 try/catch,与同步代码一致
  • 可在异步流程中使用 break、continute、return 等控制语句
  1. 缺点:
  • 多个无依赖关系的异步任务并行执行需要额外操作(Promsie.all)

5.代码实现

5.1 基于Generator和 Promise 实现 async/await

  1. 准备一个函数,参数是 generator 函数,返回值是 Promise,模拟 async
javascript 复制代码
const asyncGenerator = (generatorFunc) => {
    return new Promise((resolve,reject) => {

    })
}
  1. Generator需要手动驱动迭代器执行,包装的方法的核心是自动驱动迭代器执行
javascript 复制代码
const asyncGenerator = (generatorFunc) => {
    return new Promise((resolve,reject) => {
        // 返回一个迭代器,具备 value 和 done 属性
        const generator = generatorFunc()

        <!-- 用递归驱动迭代器自动执行 -->
        const step = (methos,val) => {
            let result = null
            result = generator[methos](val)

            const {value.done} = result
            if(done) {
                return resolve(value)
            }
        }

        step("next")
    })
}
  1. 将 yield 值包装成 Promise
javascript 复制代码
const asyncGenerator = (generatorFunc) => {
    return new Promise((resolve,reject) => {
        // 返回一个迭代器,具备 value 和 done 属性
        const generator = generatorFunc()

        <!-- 用递归驱动迭代器自动执行 -->
        const step = (methos,val) => {
            let result = null
            result = generator[methos](val)

            const {value.done} = result
            if(done) {
                return resolve(value)
            }

            Promise.resolve(value)

        }
        step("next")
    })
}

4.对于 Generator异常机制,Generator函数内部 没有 try/catch,使用 g.throw,则外部捕获错误,Generator函数内部 有 try/catch,使用 g.throw,则内部捕获错误。对于同步代码错误也需要异常捕获,如下

typescript 复制代码
const asyncGenerator = (generatorFunc) => {
    return new Promise((resolve,reject) => {
        // 返回一个迭代器,具备 value 和 done 属性
        const generator = generatorFunc()

        <!-- 用递归驱动迭代器自动执行 -->
        const step = (methos,val) => {
            let result = null
            try {
                result = generator[methos](val)
            } catch(err) {
                return reject(err)
            }
            

            const {value.done} = result
            if(done) {
                return resolve(value)
            }

            Promise.resolve(value)
            .then(val => step("next",val))
            .catch(error => step("throw",error))

        }
        step("next")
    })
}
  1. 完整代码和注释
typescript 复制代码
// 实现基于Generator的async/await
const asyncGenerator = (generatorFunc) => {
// 返回一个 Promise对象,模拟 async 的返回值
    return new Promise((resolve,reject) => {
        // 执行Generator,返回迭代器
        const generator = generatorFunc()

        // 准备递归函数,自动执行迭代器
        const step = (method,arg) => {

            let result = null
            try {
                // 执行迭代器的 next 或者 throw 方法
                result = generator[method](arg)
            } catch(error) {
                // 捕获同步代码错误,执行 reject 将错误抛出外部
                return reject(error)
            }

            const {value,done} = result

            // 若迭代器已经完成,则返回值并停止递归
            if(done) {
                return resolve(value)
            }

            // 将 yield 的结果包装成 Promise对象
            Promise.resolve(value)
            .then(
                // 成功,则把值传递给下一代
                val => step("next",val)
            ).catch(
                // 失败则捕获错误
                // Generator函数内部 没有 try/catch,使用 g.throw,则外部捕获错误
                // Generator函数内部 有 try/catch,使用 g.throw多个,则内部捕获错误一个,其他外部捕获
                error =>step("throw",error)
            )
        }
        // 开始启动迭代
        step("next")
    })
}

5.2 Promise 实现 ajax 封装

  1. 创建一个函数,参数是请求选项值,返回值是一个 Promise。处理传递的参数,默认值设置
javascript 复制代码
const ajaxPromise = (options) => {
    return new Promise((resolve,reject) => {
        if(!options || !options.url) {
            reject(new Error('URL is required'));
            return
        }
        const defaults = {
            method: "GET",
            data: null,
            headers: {},
            responseType: ''
        }

        const config = {...defaults,...options} 

        config.method = config.method.toUpperCase() 
    })
}
  1. 初始化请求并设置参数
javascript 复制代码
const ajaxPromise = (options) => {
    return new Promise((resolve,reject) => {
        ...
        // 2. 初始化请求并设置参数
        // 创建 XMLHttpRequest 对象
        const xhr = new XMLHttpRequest()

        // 2.1 初始化请求
        let requestUrl = config.url
        // GET请求需要处理 url
        if(config.method === "GET" && config.data) {
            const params = new URLSearchParams()

            for(const key in config.data) {
                params.append(key,config.data[key])
            }
            
            requestUrl = `${config.url}${config.url.includes("?")?"&":"?"}${params.toString()}`
        }

        xhr.open(config.method.toUpperCase(),requestUrl,true)

        // 2.2 设置响应类型
        if(config.responseType) {
            xhr.responseType = config.responseType
        }
        
        // 2.3 设置请求头
        for(const key in config.headers) {
            xhr.setRequestHeader(key,config.headers[key])
        }

        // 2.4 设置超时
        if(config.timeout) {
            xhr.timeout = config.timeout
        }

        // 2.5 处理状态变化
        xhr.onreadystatechange = () => {
            // 4的状态是请求完成未成功
            if(xhr.readyState !== 4) return

            // 请求成功
            if(xhr.status >= 200 && xhr.status < 300) {
                // 响应数据进行处理
                let responseData;

                if(xhr.responseType === "json") {
                    responseData = xhr.response
                } else {
                    try {
                        responseData = JSON.parse(xhr.responseText)
                    } catch (error) {
                        responseData = xhr.responseText
                    }
                }
                resolve({
                    data: responseData,
                    status: xhr.status,
                    statusText: xhr.statusText,
                    xhr: xhr
                  });

            } else {
                // 请求失败
                reject({
                    status: xhr.status,
                    statusText: xhr.statusText,
                    response: xhr.response,
                    xhr: xhr,
                    error: new Error(`Request failed with status ${xhr.status}: ${xhr.statusText}`)
                });
            }

        }
    })
}
  1. 处理网络错误
javascript 复制代码
const ajaxPromise = (options) => {
    return new Promise((resolve,reject) => {
        ...
        xhr.onerror = function() {
            reject({
                error: new Error('Network error occurred'),
                xhr: xhr
            });
        }
    })
}
  1. 超时处理
javascript 复制代码
const ajaxPromise = (options) => {
    return new Promise((resolve,reject) => {
        ...
        let timeoutTimer;
        if(config.timeout) {
            timeoutTimer = setTimeout(() => {
                xhr.abort()
                reject({
                    error: new Error('Request timed out'),
                    xhr: xhr
                });
            },timeout)
        }
    })
}
  1. 发送请求
scss 复制代码
const ajaxPromise = (options) => {
    return new Promise((resolve,reject) => {
        ...
        // 5.发送请求
        try {
            // 5.1 对于不同的请求方法,POST/PUT/PATCH,需要设置请求体
            if(config.method === "POST" || config.method  === "PUT" || config.method  === "PATCH") {

                if(!config.headers['Content-Type']) {

                    config.headers['Content-Type'] = "application/json"

                    xhr.setRequestHeader("Content-Type","application/json")
                }

                const contentType = config.headers['Content-Type'] || ''

                let requestData = config.data

                if(contentType.includes("application/json") && config.data) {

                    requestData = JSON.stringify(config.data)

                } else if(contentType.includes("application/x-www-form-urlencoded") && config.data) {

                    const params = new URLSearchParams()

                    for(let key in config.data) {

                        params.append(key,config.data[key])
                    }
                    requestData = params.toString()
                }
                xhr.send(requestData)
            } else {
                // 5.2 GET请求
                xhr.send()
            }

        } catch (error) {
            // 清除超时定时器
            if(timeoutTimer) {
                clearTimeout(timeoutTimer)
            }
            reject(error)
        }
    })
}
  1. 实现快捷请求方法
kotlin 复制代码
ajaxPromise.get = (url,data,options = {}) => {
    return  ajaxPromise({...options,url,method:"GET",data})
}

ajaxPromise.post = (url,data,options = {}) => {
    return  ajaxPromise({...options,url,method:"POST",data})
}

7.完整代码

scss 复制代码
const ajaxPromise = (options) => {
    return new Promise((resolve,reject) => {
        // 1.处理传递的参数,默认值设置
        if(!options || !options.url) {
            reject(new Error('URL is required'));
            return
        }
        const defaults = {
            method: "GET",
            data: null,
            headers: {},
            responseType: ''
        }

        const config = {...defaults,...options} 

        config.method = config.method.toUpperCase() 

        // 2. 初始化请求并设置参数
        // 创建 XMLHttpRequest 对象
        const xhr = new XMLHttpRequest()

        // 2.1 初始化请求
        let requestUrl = config.url
        // GET请求需要处理 url
        if(config.method === "GET" && config.data) {
            const params = new URLSearchParams()

            for(const key in config.data) {
                params.append(key,config.data[key])
            }
            
            requestUrl = `${config.url}${config.url.includes("?")?"&":"?"}${params.toString()}`
        }

        xhr.open(config.method.toUpperCase(),requestUrl,true)

        // 2.2 设置响应类型
        if(config.responseType) {
            xhr.responseType = config.responseType
        }
        
        // 2.3 设置请求头
        for(const key in config.headers) {
            xhr.setRequestHeader(key,config.headers[key])
        }

        // 2.4 设置超时
        if(config.timeout) {
            xhr.timeout = config.timeout
        }

        // 2.5 处理状态变化
        xhr.onreadystatechange = () => {
            // 4的状态是请求完成未成功
            if(xhr.readyState !== 4) return

            // 请求完成,清除超时定时器
            if(timeoutTimer) {
                clearTimeout(timeoutTimer)
            }
            

            // 请求成功
            if(xhr.status >= 200 && xhr.status < 300) {
                // 响应数据进行处理
                let responseData;

                if(xhr.responseType === "json") {
                    responseData = xhr.response
                } else {
                    try {
                        responseData = JSON.parse(xhr.responseText)
                    } catch (error) {
                        responseData = xhr.responseText
                    }
                }
                resolve({
                    data: responseData,
                    status: xhr.status,
                    statusText: xhr.statusText,
                    xhr: xhr
                  });

            } else {
                // 请求失败
                reject({
                    status: xhr.status,
                    statusText: xhr.statusText,
                    response: xhr.response,
                    xhr: xhr,
                    error: new Error(`Request failed with status ${xhr.status}: ${xhr.statusText}`)
                });
            }

        }
        // 3.处理网络错误
        xhr.onerror = function() {
            // 清除超时定时器
            if(timeoutTimer) {
                clearTimeout(timeoutTimer)
            }
            reject({
                error: new Error('Network error occurred'),
                xhr: xhr
            });
        }

        // 4.超时处理
        let timeoutTimer;
        if(config.timeout) {
            timeoutTimer = setTimeout(() => {
                xhr.abort()
                reject({
                    error: new Error('Request timed out'),
                    xhr: xhr
                });
            },timeout)
        }

        // 5.发送请求
        try {
            // 5.1 对于不同的请求方法,POST/PUT/PATCH,需要设置请求体
            if(config.method === "POST" || config.method  === "PUT" || config.method  === "PATCH") {

                if(!config.headers['Content-Type']) {

                    config.headers['Content-Type'] = "application/json"

                    xhr.setRequestHeader("Content-Type","application/json")
                }

                const contentType = config.headers['Content-Type'] || ''

                let requestData = config.data

                if(contentType.includes("application/json") && config.data) {

                    requestData = JSON.stringify(config.data)

                } else if(contentType.includes("application/x-www-form-urlencoded") && config.data) {

                    const params = new URLSearchParams()

                    for(let key in config.data) {

                        params.append(key,config.data[key])
                    }
                    requestData = params.toString()
                }
                xhr.send(requestData)
            } else {
                // 5.2 GET请求
                xhr.send()
            }

        } catch (error) {
            // 清除超时定时器
            if(timeoutTimer) {
                clearTimeout(timeoutTimer)
            }
            reject(error)
        }
    })
}

ajaxPromise.get = (url,data,options = {}) => {
    return  ajaxPromise({...options,url,method:"GET",data})
}

ajaxPromise.post = (url,data,options = {}) => {
    return  ajaxPromise({...options,url,method:"POST",data})
}

module.exports = ajaxPromise;

6.测试验证

单元测试,使用了Jest框架,下面是测试的几个测试用例,完全通过

6.1 实现 async/await 单元测试

javascript 复制代码
const asyncGenerator = require('../xxx');

// 辅助函数:模拟异步操作
function delay(ms, value) {
  return new Promise(resolve => {
    setTimeout(() => resolve(value), ms);
  });
}

// 辅助函数:模拟失败的异步操作
function failAfter(ms, errorMessage) {
  return new Promise((resolve, reject) => {
    setTimeout(() => reject(new Error(errorMessage)), ms);
  });
}

describe('asyncGenerator', () => {
  // 测试1:基本功能 - 执行简单的Generator函数
  test('should execute a simple generator function', async () => {
    function* simpleGenerator() {
      yield 1;
      yield 2;
      return 3;
    }

    const result = await asyncGenerator(simpleGenerator);
    expect(result).toBe(3);
  });

  // 测试2:处理同步值
  test('should handle synchronous values', async () => {
    function* syncGenerator() {
      const a = yield 10;
      const b = yield 20;
      return a + b;
    }

    const result = await asyncGenerator(syncGenerator);
    expect(result).toBe(30);
  });

  // 测试3:处理单个异步操作
  test('should handle a single asynchronous operation', async () => {
    function* asyncGeneratorFunc() {
      const result = yield delay(10, 'test');
      return result;
    }

    const result = await asyncGenerator(asyncGeneratorFunc);
    expect(result).toBe('test');
  });

  // 测试4:处理多个串行异步操作
  test('should handle multiple sequential async operations', async () => {
    function* serialAsyncGenerator() {
      const result1 = yield delay(10, 'first');
      const result2 = yield delay(10, 'second');
      const result3 = yield delay(10, 'third');
      return [result1, result2, result3];
    }

    const result = await asyncGenerator(serialAsyncGenerator);
    expect(result).toEqual(['first', 'second', 'third']);
  });

  // 测试5:处理异步操作的返回值传递
  test('should pass values between async operations', async () => {
    function* valuePassingGenerator() {
      const num1 = yield delay(10, 10);
      const num2 = yield delay(10, 20);
      return num1 + num2;
    }

    const result = await asyncGenerator(valuePassingGenerator);
    expect(result).toBe(30);
  });

  // 测试6:捕获异步操作的错误(外部捕获)
  test('should catch async errors in external catch', async () => {
    function* errorGenerator() {
      yield failAfter(10, 'Async error');
    }

    await expect(asyncGenerator(errorGenerator)).rejects.toThrow('Async error');
  });

  // 测试7:在Generator内部捕获错误
  test('should allow catching errors inside generator', async () => {
    function* errorHandlingGenerator() {
      try {
        yield failAfter(10, 'Expected error');
        return 'This should not be reached';
      } catch (error) {
        return `Caught error: ${error.message}`;
      }
    }

    const result = await asyncGenerator(errorHandlingGenerator);
    expect(result).toBe('Caught error: Expected error');
  });

  // 测试8:处理同步错误
  test('should handle synchronous errors', async () => {
    function* syncErrorGenerator() {
      yield 1;
      throw new Error('Sync error');
      yield 2; // 不会执行
    }

    await expect(asyncGenerator(syncErrorGenerator)).rejects.toThrow('Sync error');
  });

  // 测试9:错误处理后继续执行
  test('should continue execution after error handling', async () => {
    function* continueAfterErrorGenerator() {
      let result;
      
      try {
        yield failAfter(10, 'Temporary error');
      } catch (error) {
        result = error.message;
      }
      
      const recovery = yield delay(10, 'Recovered');
      return `${result}: ${recovery}`;
    }

    const result = await asyncGenerator(continueAfterErrorGenerator);
    expect(result).toBe('Temporary error: Recovered');
  });
});

6.2 Promise 实现 ajax 封装 单元测试

ini 复制代码
const ajax = require('../4.ajaxPromise');
// 模拟XMLHttpRequest
class MockXHR {

  // 静态属性用于保存实例引用
  static instance;

  constructor() {
    // 创建实例时保存到静态属性
    MockXHR.instance = this;

    this.method = null;
    this.url = null;
    this.async = true;
    this.headers = {};
    this.responseType = '';
    this.status = 0;
    this.statusText = 'OK';
    this.response = null;
    this.responseText = '';
    this.readyState = 0;
    this.onreadystatechange = null;
    this.onerror = null;
    this.ontimeout = null;
  }

  open(method, url, async) {
    this.method = method;
    this.url = url;
    this.async = async;
    this.readyState = 1;
  }

  setRequestHeader(key, value) {
    this.headers[key] = value;
  }

  send(data) {
    this.sendData = data;
    // 模拟异步完成
    setTimeout(() => {
      this.readyState = 4;
      if (this.onreadystatechange) {
        this.onreadystatechange();
      }
    }, 0);
  }

  // 辅助方法,用于测试控制响应
  setResponse(status, response, responseType = 'text') {
    this.status = status;
    this.responseType = responseType;
    this.response = response;
    this.responseText = typeof response === 'string' ? response : JSON.stringify(response);
  }
}

// 替换全局XMLHttpRequest
beforeEach(() => {
  global.XMLHttpRequest = MockXHR;
  MockXHR.instance = null;
});

describe('ajax', () => {
    it('应该处理网络错误', async () => {
        // 发送请求
        const promise = ajax({
          url: 'https://api.example.com/network-error',
          method: 'GET'
        });
        
        // 获取XHR实例并触发错误
        const xhr =  MockXHR.instance;
        
        // 模拟网络错误
        setTimeout(() => {
            if (xhr.onerror) {
                xhr.onerror();
            }
        }, 0);
        
        // 验证错误
        await expect(promise).rejects.toHaveProperty('error');
        await expect(promise).rejects.toMatchObject({
          error: expect.any(Error)
        });
      });
  it('应该发送GET请求并成功返回', async () => {
    const mockResponse = { data: 'test' };
    
    // 发送请求
    const promise = ajax({
      url: 'https://api.example.com/test',
      method: 'GET'
    });
    
    // 获取最后创建的XHR实例并设置响应
    const xhr =  MockXHR.instance;
    xhr.setResponse(200, mockResponse);
    
    // 等待Promise完成
    const result = await promise;
    
    // 验证结果
    expect(result.data).toEqual(mockResponse);
    expect(result.status).toBe(200);
    expect(xhr.method).toBe('GET');
    expect(xhr.url).toBe('https://api.example.com/test');
  });

  it('应该发送POST请求并成功返回', async () => {
    const postData = { name: 'test' };
    const mockResponse = { success: true };
    
    // 发送请求
    const promise = ajax({
      url: 'https://api.example.com/submit',
      method: 'POST',
      data: postData
    });
    
    // 获取XHR实例并设置响应
    const xhr =  MockXHR.instance;
    xhr.setResponse(201, mockResponse);
    
    // 等待结果
    const result = await promise;
    
    // 验证
    expect(result.data).toEqual(mockResponse);
    expect(result.status).toBe(201);
    expect(xhr.method).toBe('POST');
    expect(xhr.sendData).toBe(JSON.stringify(postData));
    expect(xhr.headers['Content-Type']).toBe('application/json');
  });

  it('应该处理请求错误', async () => {
    const errorMessage = 'Not Found';
    
    // 发送请求
    const promise = ajax({
      url: 'https://api.example.com/error',
      method: 'GET'
    });
    
    // 获取XHR实例并设置错误响应
    const xhr =  MockXHR.instance;
    xhr.setResponse(404, errorMessage);
    
    // 验证错误
    await expect(promise).rejects.toHaveProperty('status', 404);
    await expect(promise).rejects.toHaveProperty('response', errorMessage);
  });

  

  it('应该处理GET请求的查询参数', async () => {
    const queryParams = { id: 123, name: 'test' };
    
    // 发送请求
    const promise = ajax({
      url: 'https://api.example.com/data',
      method: 'GET',
      data: queryParams
    });
    
    // 获取XHR实例并设置响应
    const xhr =  MockXHR.instance;
    xhr.setResponse(200, { success: true });
    
    // 等待结果
    await promise;
    
    // 验证URL包含查询参数
    expect(xhr.url).toBe('https://api.example.com/data?id=123&name=test');
  });

  it('应该支持便捷的get方法', async () => {
    // 使用便捷方法发送请求
    const promise = ajax.get('https://api.example.com/get-test', { param: 'value' });
    
    // 获取XHR实例并设置响应
    const xhr =  MockXHR.instance;
    xhr.setResponse(200, { result: 'success' });
    
    // 验证
    const result = await promise;
    expect(xhr.method).toBe('GET');
    expect(result.data).toEqual({ result: 'success' });
  });

  it('应该支持便捷的post方法', async () => {
    // 使用便捷方法发送请求
    const promise = ajax.post('https://api.example.com/post-test', { data: 'value' });
    
    // 获取XHR实例并设置响应
    const xhr =  MockXHR.instance;
    xhr.setResponse(200, { result: 'success' });
    
    // 验证
    const result = await promise;
    expect(xhr.method).toBe('POST');
    expect(result.data).toEqual({ result: 'success' });
  });

  it('应该正确解析JSON响应', async () => {
    const jsonResponse = { name: 'test', value: 123 };
    
    // 发送请求
    const promise = ajax({
      url: 'https://api.example.com/json',
      method: 'GET'
    });
    
    // 获取XHR实例并设置响应,模拟Content-Type为JSON
    const xhr =  MockXHR.instance;
    xhr.getResponseHeader = jest.fn(() => 'application/json');
    xhr.setResponse(200, jsonResponse);
    
    // 等待结果
    const result = await promise;
    
    // 验证JSON被正确解析
    expect(result.data).toEqual(jsonResponse);
    expect(typeof result.data).toBe('object');
  });
});
    

7.总结

我们对三大异步编程方案进行了横向对比,在日常开发中就可以轻松选择在什么场景使用哪种异步解决方案,三个异步编程方案是层层递进式的,从最初的回调函数(callback)->Promise(解决回调地狱)->Generator(异步线性化思路)->async/await(终极简化,实现以同步方式编写异步代码)。大多数场景中,使用 async/await + Promise 是最优组合,使用async/await串行处理异步流程,用 Promise.all()处理并行任务,兼容可读性和效率。

相关推荐
Miracle_G41 分钟前
每日一个知识点:JavaScript 箭头函数与普通函数比较
javascript
unfetteredman41 分钟前
Error: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found
前端·javascript·vite
程序员小续2 小时前
React 官方严令禁止:Hook 不能写在 if/else,真相竟然是…
前端·javascript·程序员
尝尝你的优乐美3 小时前
封装那些Vue3.0中好用的指令
前端·javascript·vue.js
敲代码的彭于晏3 小时前
localStorage 不够用?试试 IndexedDB !
前端·javascript·浏览器
chxii3 小时前
5.4 4pnpm 使用介绍
前端·javascript·vue.js
cxyxiaokui0013 小时前
别让你的Java对象在内存里躺平!序列化带它看世界
后端·面试
米开朗积德3 小时前
项目多文件JSON数值比对
javascript
sorryhc3 小时前
【AI解读源码系列】ant design mobile——Image图片
前端·javascript·react.js