前端异步(async)解决方案(所有方案)(二)

简介: 前端异步(async)解决方案(所有方案)

3):Promise.all()

Promise.all()接收一个参数,它必须是可以迭代的,比如数组。

它通常用来处理一些并发的异步操作,即它们的结果互不干扰,但是又需要异步执行。它最终只有两种状态:成功或者失败。


指的是将数组中所有的任务执行完成之后, 才执行.then 中的任务


它的状态受参数内各个值的状态影响,即里面状态全部为fulfilled时,它才会变成fulfilled,否则变成rejected。


成功调用后返回一个数组,数组的值是有序的,即按照传入参数的数组的值操作后返回的结果。


如下:

constp1=newPromise((resolve,reject)=>{
setTimeout(()=>{
resolve(console.log('p1 任务1'))
  },1000)
})
  .then( data=> {
console.log('p1 任务2')
  })
  .then( res=> {
console.log('p1 任务3')
  })
  .catch( err=>{ throwerr} )
constp2=newPromise((resolve,reject)=>{
resolve(console.log('p2 任务1'))
}).then(
data=> {
console.log('p2 任务2')
  }
).catch(
err=> {
throwerr  }
)
//只有在p1,p2都执行完后才会执行then里的内容Promise.all([p1,p2])
 .then(()=>console.log('done'))

4):Promise.race()


Promise.race()和Promise.all()类似,都接收一个可以迭代的参数,但是不同之处是Promise.race()的状态变化不是全部受参数内的状态影响,一旦参数内有一个值的状态发生的改变,那么该Promise的状态就是改变的状态。就跟race单词的字面意思一样,谁跑的快谁赢。如下:

varp1=newPromise(function(resolve, reject) {
setTimeout(resolve, 300, 'p1 doned');
});
varp2=newPromise(function(resolve, reject) {
setTimeout(resolve, 50, 'p2 doned');
});
varp3=newPromise(function(resolve, reject) {
setTimeout(reject, 100, 'p3 rejected');
});
Promise.race([p1, p2, p3]).then(function(data) {
// 显然p2更快,所以状态变成了fulfilled// 如果p3更快,那么状态就会变成rejectedconsole.log(data); // p2 doned}).catch(function(err) {
console.log(err); // 不执行});

5):Promise.resolve()


Promise.resolve()接受一个参数值,可以是普通的值,具有then()方法的对象和Promise实例。正常情况下,它返回一个Promise对象,状态为fulfilled。但是,当解析时发生错误时,返回的Promise对象将会置为rejected态。如下:

// 参数为普通值varp4=Promise.resolve(5);
p4.then(function(data) {
console.log(data); // 5});
// 参数为含有then()方法的对象varobj= {
then: function() {
console.log('obj 里面的then()方法');
  }
};
varp5=Promise.resolve(obj);
p5.then(function(data) {
// 这里的值时obj方法里面返回的值console.log(data); // obj 里面的then()方法});
// 参数为Promise实例varp6=Promise.resolve(7);
varp7=Promise.resolve(p6);
p7.then(function(data) {
// 这里的值时Promise实例返回的值console.log(data); // 7});
// 参数为Promise实例,但参数是rejected态varp8=Promise.reject(8);
varp9=Promise.resolve(p8);
p9.then(function(data) {
// 这里的值时Promise实例返回的值console.log('fulfilled:'+data); // 不执行}).catch(function(err) {
console.log('rejected:'+err); // rejected: 8});

6):Promise.reject()

Promise.reject()和Promise.resolve()正好相反,它接收一个参数值reason,即发生异常的原因。此时返回的Promise对象将会置为rejected态。如下:

varp10=Promise.reject('手动拒绝');
p10.then(function(data) {
console.log(data); // 这里不会执行,因为是rejected态}).catch(function(err) {
console.log(err); // 手动拒绝}).then(function(data) {
// 不受上一级影响console.log('状态:fulfilled'); // 状态:fulfilled});

总之,除非Promise.then()方法内部抛出异常或者是明确置为rejected态,否则它返回的Promise的状态都是fulfilled态,即完成态,并且它的状态不受它的上一级的状态的影响。


2.gengerator函数


在异步编程中,还有一种常用的解决方案,它就是Generator生成器函数。顾名思义,它是一个生成器,它也是一个状态机,内部拥有值及相关的状态,生成器返回一个迭代器Iterator对象,我们可以通过这个迭代器,手动地遍历相关的值、状态,保证正确的执行顺序。

es6 提供的 generator函数


总得来说就三点:


*在function关键字后加一个* , 那么这个函数就称之为generator函数


*函数体有关键字 yield , 后面跟每一个任务 , 也可以有return关键字, 保留一个数据


*通过next函数调用, 几个调用, 就是几个人任务执行

(1).简单使用

Generator的声明方式类似一般的函数声明,只是多了个*号,并且一般可以在函数内看到yield关键字

function*showWords() {
yield'one';
yield'two';
return'three';
}
varshow=showWords();
show.next() // {done: false, value: "one"}show.next() // {done: false, value: "two"}show.next() // {done: true, value: "three"}show.next() // {value: underfined, done: true}

如上代码,定义了一个showWords的生成器函数,调用之后返回了一个迭代器对象(即show)


调用next方法后,函数内执行第一条yield语句,输出当前的状态done(迭代器是否遍历完成)以及相应值(一般为yield关键字后面的运算结果)


每调用一次next,则执行一次yield语句,并在该处暂停,return完成之后,就退出了生成器函数,后续如果还有yield操作就不再执行了


当然还有以下情况:(next()数量小于yield)

function*g1(){
yield'任务1'yield'任务2'yield'任务3'return'任务4'}
constg1done=g1()
console.log(g1done.next()) //{ value: '任务1', done: false }console.log(g1done.next()) //{ value: '任务2', done: false }

(2).yield和yield*

有时候,我们会看到yield之后跟了一个*号,它是什么,有什么用呢?

类似于生成器前面的*号,yield后面的星号也跟生成器有关,举个大栗子:

function*showWords() {
yield'one';
yieldshowNumbers();
return'three';
}
function*showNumbers() {
yield10+1;
yield12;
}
varshow=showWords();
show.next() // {done: false, value: "one"}show.next() // {done: false, value: showNumbers}show.next() // {done: true, value: "three"}show.next() // {done: true, value: undefined}

增添了一个生成器函数,我们想在showWords中调用一次,简单的 yield showNumbers()之后发现并没有执行函数里面的yield 10+1


因为yield只能原封不动地返回右边运算后值,但现在的showNumbers()不是一般的函数调用,返回的是迭代器对象


所以换个yield* 让它自动遍历进该对象

function*showWords() {
yield'one';
yield*showNumbers();
return'three';
}
function*showNumbers() {
yield10+1;
yield12;
}
varshow=showWords();
show.next() // {done: false, value: "one"}show.next() // {done: false, value: 11}show.next() // {done: false, value: 12}show.next() // {done: true, value: "three"}

要注意的是,这yield和yield* 只能在generator函数内部使用,一般的函数内使用会报错

function showWords() {
    yield 'one'; // Uncaught SyntaxError: Unexpected string
}

虽然换成yield*不会直接报错,但使用的时候还是会有问题,因为’one'字符串中没有Iterator接口,没有yield提供遍历

functionshowWords() {
yield*'one'; 
}
varshow=showWords();
show.next() // Uncaught ReferenceError: yield is not defined

在开发中,我们常常需要请求多个地址,为了保证顺序,引入Promise对象和Generator生成器函数,看这个简单的栗子:

varurls= ['url1', 'url2', 'url3'];
function*request(urls) {
urls.forEach(function(url) {
yieldreq(url);
    });
//     for (var i = 0, j = urls.length; i < j; ++i) {//         yield req(urls[i]);//     }}
varr=request(urls);
r.next();
functionreq(url) {
varp=newPromise(function(resolve, reject) {
$.get(url, function(rs) {
resolve(rs);
        });
    });
p.then(function() {
r.next();
    }).catch(function() {
    });
}

上述代码中forEach遍历url数组,匿名函数内部不能使用yield关键字,改换成注释中的for循环就行了

相关文章
|
5天前
|
前端开发 JavaScript
乾坤qiankun(微前端)样式隔离解决方案--使用插件替换前缀
乾坤qiankun(微前端)样式隔离解决方案--使用插件替换前缀
36 8
|
2天前
|
前端开发 JavaScript
前端在移动端使用 100vh 导致页面出现滚动条的解决方案
前端在移动端使用 100vh 导致页面出现滚动条的解决方案
5 1
|
9天前
|
设计模式 前端开发 JavaScript
前端编程的异步解决方案有哪些?
本文首发于微信公众号“前端徐徐”,介绍了异步编程的背景和几种常见方案,包括回调、事件监听、发布订阅、Promise、Generator、async/await和响应式编程。每种方案都有详细的例子和优缺点分析,帮助开发者根据具体需求选择最合适的异步编程方式。
18 1
|
4天前
|
缓存 前端开发 UED
前端 8 种图片加载优化方案梳理
本文首发于微信公众号“前端徐徐”,详细探讨了现代网页设计中图片加载速度优化的重要性及方法。内容涵盖图片格式选择(如JPEG、PNG、WebP等)、图片压缩技术、响应式图片、延迟加载、CDN使用、缓存控制、图像裁剪与缩放、Base64编码等前端图片优化策略,旨在帮助开发者提升网页性能和用户体验。
23 0
|
1月前
|
Web App开发 前端开发 JavaScript
Web前端项目的跨平台桌面客户端打包方案之——CEF框架
Chromium Embedded Framework (CEF) 是一个基于 Google Chromium 项目的开源 Web 浏览器控件,旨在为第三方应用提供嵌入式浏览器支持。CEF 隔离了底层 Chromium 和 Blink 的复杂性,提供了稳定的产品级 API。它支持 Windows、Linux 和 Mac 平台,不仅限于 C/C++ 接口,还支持多种语言。CEF 功能强大,性能优异,广泛应用于桌面端开发,如 QQ、微信、网易云音乐等。CEF 开源且采用 BSD 授权,商业友好,装机量已超 1 亿。此外,GitHub 项目 CefDetector 可帮助检测电脑中使用 CEF
192 3
|
2月前
|
缓存 前端开发 JavaScript
前端性能优化方案
【8月更文挑战第15天】前端性能优化方案
32 2
|
1月前
|
编解码 前端开发 JavaScript
前端移动端适配方案
【9月更文挑战第8天】前端移动端适配方案
69 0
|
2月前
|
开发者 安全 UED
JSF事件监听器:解锁动态界面的秘密武器,你真的知道如何驾驭它吗?
【8月更文挑战第31天】在构建动态用户界面时,事件监听器是实现组件间通信和响应用户操作的关键机制。JavaServer Faces (JSF) 提供了完整的事件模型,通过自定义事件监听器扩展组件行为。本文详细介绍如何在 JSF 应用中创建和使用事件监听器,提升应用的交互性和响应能力。
31 0
|
2月前
|
前端开发 JavaScript 中间件
【前端状态管理之道】React Context与Redux大对决:从原理到实践全面解析状态管理框架的选择与比较,帮你找到最适合的解决方案!
【8月更文挑战第31天】本文通过电子商务网站的具体案例,详细比较了React Context与Redux两种状态管理方案的优缺点。React Context作为轻量级API,适合小规模应用和少量状态共享,实现简单快捷。Redux则适用于大型复杂应用,具备严格的状态管理规则和丰富的社区支持,但配置较为繁琐。文章提供了两种方案的具体实现代码,并从适用场景、维护成本及社区支持三方面进行对比分析,帮助开发者根据项目需求选择最佳方案。
36 0
|
2月前
|
前端开发 JavaScript 开发者
探索前端开发中的异步编程:Promise与Async/Await
在现代前端开发中,处理异步操作是至关重要的。本文将深入探讨异步编程的核心概念,重点比较JavaScript中的Promise与Async/Await两种异步编程方式。通过实例和比较,读者将能够理解这两种方法的优缺点,如何在实际开发中选择适合的异步编程模式,从而编写更简洁、可维护的代码。