【JavaScript】掌握异步编程,看这里!
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
异步处理的概念JavaScript 中的异步处理指的是在代码执行过程中,能够不阻塞当前线程并处理一些时间较长的操作。异步处理通常涉及到回调函数、Promise、async/await 等机制。 在 JavaScript 中,传统的同步处理方式采用的是阻塞式的单线程模型。这种模型的缺点是当一个任务被执行时,它会一直执行到结束,期间如果有耗时的操作也会一直阻塞下去,直到任务执行完毕,才会执行后续的任务。这种方式会导致页面卡死,体验非常不好。 因此,JavaScript 异步处理机制应运而生,它允许在代码执行过程中,执行一些耗时的操作,而不会阻塞当前线程。 回调函数回调函数是一种很常见的异步编程模型,通过在异步操作完成后调用回调函数来通知异步操作已结束,从而执行后续的任务。例如: function fetchData(callback) { setTimeout(function() { const data = { name: '张三', age: 20 }; callback(data); }, 1000); } fetchData(function(data) { console.log(data); }); 在这个示例中,fetchData() 函数在完成数据加载后,调用回调函数 callback() 并传递数据作为参数。当数据加载完成后,控制器会跳转到回调函数中执行后续任务。 PromisePromise 是一种比较流行的异步编程模型,它可以在异步操作完成后执行一些回调操作,并将结果返回给请求方。Promise 代表了一个异步操作的最终完成(或失败)及其结果值。例如: function fetchData() { return new Promise(function(resolve, reject) { setTimeout(function() { const data = { name: '张三', age: 20 }; resolve(data); }, 1000); }); } fetchData().then(function(data) { console.log(data); }); 异步处理常见场景与处理策略异步处理常见场景包括但不限于:
JavaScript 引擎是单线程执行的,也就是说同一时间内只有一个任务在执行。当需要进行异步操作时,通常会使用回调函数。 假设我们有一个获取用户信息的异步函数 getUserInfo,在信息获取完成后需要调用相关回调函数。一种实现方式是将回调函数作为 getUserInfo 函数的第二个参数传入,信息获取完成后调用该函数。 function getUserInfo(userId, callback) { setTimeout(function() { const userInfo = { id: userId, name: "Tom", age: 25 } callback(userInfo) }, 1000) } getUserInfo(1001, function(userInfo) { console.log(userInfo) }) 上述代码首先调用 getUserInfo 函数,该函数通过 setTimeout 模拟异步操作,等待 1 秒钟后获取用户信息,并在信息获取完成后调用传入的回调函数。最后在回调函数中输出用户信息。 Promise A+ 规范 Promise 的状态 一个 Promise 的当前状态必须为以下三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和 拒绝态(Rejected)。
一个 promise 必须提供一个 then 方法以访问其当前值、终值和据因。 promise 的 then 方法接受两个参数: promise.then(onFulfilled, onRejected); 其中,onFulfilled 和 onRejected 都是可选参数。
发布-订阅模式 根据 Promise A+ 规范,每次 then 返回的值也需要满足 thenable,也就是说我们需要将 resolve 返回值使用 promise 包裹,在本例中就是需要将返回值包装为新的 HePromise 对象。开发之前我们不妨先来看看 Promise 链式调用的示例: const p = new Promise(resolve => resolve(1)); p.then(r1 => { console.log(r1); return 2; }) .then(r2 => { console.log(r2); return 3; }) .then(r3 => { console.log(r3); }); 实现all方法就是将传入数组中的值 promise 化,然后保证每个任务都处理后,最终 resolve。示例如下: class HePromise { static all(promises: any[]) { let index = 0; const result: any[] = []; const pLen = promises.length; return new HePromise((resolve, reject) => { promises.forEach(p => { HePromise.resolve(p).then( val => { index++; result.push(val); if (index === pLen) { resolve(result); } }, err => { if (reject) reject(err); }, ); }); }); } } 编写测试用例如下: it('HePromise.all', done => { HePromise.all([1, 2, 3]).then(res => { expect(res).toEqual([1, 2, 3]); done(); }); }); 执行测试,测试通过。 实现race方法就是将传入数组中的值 promise 化,只要其中一个任务完成,即可 resolve。示例如下: class HePromise { static race(promises: any[]): HePromise { return new HePromise((resolve, reject) => { promises.forEach(p => { HePromise.resolve(p).then( val => { resolve(val); }, err => { if (reject) reject(err); }, ); }); }); } } 编写测试用例: it('HePromise.race', done => { HePromise.race([11, 22, 33]).then(res => { expect(res).toBe(11); done(); }); });
整体测试代码情况如下: async 与 await 用法及原理详解async function test() { const res = await Promise.resolve(1) return res } 需要注意的是,使用 async、await 处理异步操作时,需要注意异常的处理。 异常处理通常我们使用 try、catch 捕获 async、await 执行过程中抛出的异常,就像这样: async function test() { let res = null try { const res = await Promise.resolve(1) return res } catch(e) { console.log(e) } } 从零实现一个类似 async、await 的函数 promise+generator function fn(nums) { return new Promise(resolve = >{ setTimeout(() = >{ resolve(nums * 2) }, 1000) }) } function * gen() { const num1 = yield fn(1) const num2 = yield fn(num1) const num3 = yield fn(num2) return num3 } function generatorToAsync(generatorFn) { return function() { return new Promise((resolve, reject) = >{ const g = generatorFn() const next1 = g.next() next1.value.then(res1 = >{ const next2 = g.next(res1) // 传入上次的res1 next2.value.then(res2 = >{ const next3 = g.next(res2) // 传入上次的res2 next3.value.then(res3 = >{ // 传入上次的res3 resolve(g.next(res3).value) }) }) }) }) } } const asyncFn = generatorToAsync(gen) asyncFn().then(res = >console.log(res)) // 3秒后输出 8 自动执行 自动执行其实就是运用递归,将生成器函数产生的数据不断调用 next,直至执行完成。 function getData(endpoint) { return new Promise(resolve => { setTimeout(() => { resolve(`Data received from ${endpoint}`) }, 2000) }) } // 生成器函数 function* getDataAsync() { const result1 = yield getData('Endpoint 1') console.log(result1) const result2 = yield getData('Endpoint 2') console.log(result2) return 'All data received' } // 将生成器函数包装成 Promise function asyncToPromise(generatorFn) { const generator = generatorFn() function handleResult(result) { if (result.done) { return Promise.resolve(result.value) } return Promise.resolve(result.value) .then(res => handleResult(generator.next(res))) .catch(err => handleResult(generator.throw(err))) } try { return handleResult(generator.next()) } catch (error) { return Promise.reject(error) } } asyncToPromise(getDataAsync).then(result => console.log(result))
该文章在 2024/3/29 23:46:43 编辑过 |
关键字查询
相关文章
正在查询... |