async / await:更好的异步解决方案

2017/07/27 · JavaScript
· async,
await

原文出处: 波同学   

在实际开发中总会遇到许多异步的问题,最常见的场景接口请求之后一定要等一段时间才能得到结果,如果遇到多个接口前后依赖,那么问题就变得复杂。大家都一直在尝试使用更好的方案来解决这些问题。最开始只能利用回调函数,后来开始有人使用Promise的思维来搞定。到ES6中开始支持原生的Promise,引入Generator函数。

直到ES7,有了async/await。

这是一个用同步的思维来解决异步问题的方案。

我想很多人可能还不太分得清同步与异步的区别。如果你已经彻底了解了事件循环,那么想必对异步的概念应该非常了解。当我们发出了请求,并不会等待响应结果,而是会继续执行后面的代码,响应结果的处理在之后的事件循环中解决。那么同步的意思,就是等结果出来之后,代码才会继续往下执行。

我们可以用一个两人问答的场景来比喻异步与同步。A向B问了一个问题之后,不等待B的回答,接着问下一个问题,这是异步。A向B问了一个问题之后,然后就笑呵呵的等着B回答,B回答了之后他才会接着问下一个问题。

那么我们先记住这个特点,async/await使用同步的思维,来解决异步的问题。在继续讲解它的语法与使用之前,我们先介绍一下如何在我们的开发环境中支持该语法。

如果你已经知道如何配置,可跳过

用信号来控制异步流程

2017/08/08 · JavaScript
· 异步

原文出处:
十年踪迹   

  • 总结

我们知道,JavaScript 不管是操作
DOM,还是执行服务端任务,不可避免需要处理许多异步调用。在早期,许多开发者仅仅通过
JavaScript 的回调方式来处理异步,但是那样很容易造成异步回调的嵌套,产生
“Callback Hell”。

图片 1

后来,一些开发者使用了 Promise
思想来避免异步回调的嵌套,社区将根据思想提出 Promise/A+ 规范,最终,在
ES6 中内置实现了 Promise 类,随后又基于 Promise 类在 ES2017 里实现了
async/await,形成了现在非常简洁的异步处理方式。

比如 thinkJS 下面这段代码就是典型的 async/await
用法,它看起来和同步的写法完全一样,只是增加了 async/await 关键字。

module.exports = class extends think.Controller { async indexAction(){
let model = this.model(‘user’); try{ await model.startTrans(); let
userId = await model.add({name: ‘xxx’}); let insertId = await
this.model(‘user_group’).add({user_id: userId, group_id: 1000});
await model.commit(); }catch(e){ await model.rollback(); } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = class extends think.Controller {
  async indexAction(){
    let model = this.model(‘user’);
    try{
      await model.startTrans();
      let userId = await model.add({name: ‘xxx’});
      let insertId = await this.model(‘user_group’).add({user_id: userId, group_id: 1000});
      await model.commit();
    }catch(e){
      await model.rollback();
    }
  }
}

async/await 可以算是一种语法糖,它将

promise.then(res => { do sth. }).catch(err => { some error })

1
2
3
4
5
promise.then(res => {
    do sth.
}).catch(err => {
    some error
})

转换成了

try{ res = await promise do sth }catch(err){ some error }

1
2
3
4
5
6
try{
    res = await promise
    do sth
}catch(err){
    some error
}

有了 async,await,可以写出原来很难写出的非常简单直观的代码:

JS Bin on jsbin.com

function idle(time){ return new Promise(resolve=>setTimeout(resolve,
time)) } (async function(){ //noprotect do { traffic.className = ‘stop’
await idle(1000) traffic.className = ‘pass’ await idle(1500)
traffic.className = ‘wait’ await idle(500) }while(1) })()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function idle(time){
  return new Promise(resolve=>setTimeout(resolve, time))
}
 
(async function(){
  //noprotect
  do {
    traffic.className = ‘stop’
    await idle(1000)
    traffic.className = ‘pass’
    await idle(1500)
    traffic.className = ‘wait’
    await idle(500)
  }while(1)
})()

上面的代码中,我们利用异步的 setTimeout 实现了一个 idle 的异步方法,返回
promise。许多异步处理过程都能让它们返回
promise,从而产生更简单直观的代码。

网页中的 JavaScript
还有一个问题,就是我们要响应很多异步事件,表示用户操作的异步事件其实不太好改写成
promise,事件代表控制,它和数据与流程往往是两个层面的事情,所以许多现代框架和库通过绑定机制把这一块封装起来,让开发者能够聚焦于操作数据和状态,从而避免增加系统的复杂度。

比如上面那个“交通灯”,这样写已经是很简单,但是如果我们要增加几个“开关”,表示“暂停/继续“和”开启/关闭”,要怎么做呢?如果我们还想要增加开关,人工控制和切换灯的转换,又该怎么实现呢?

有同学想到这里,可能觉得,哎呀这太麻烦了,用 async/await
搞不定,还是用之前传统的方式去实现吧。

其实即使用“传统”的思路,要实现这样的异步状态控制也还是挺麻烦的,但是我们的
PM 其实也经常会有这样麻烦的需求。

我们试着来实现一下:

JS Bin on jsbin.com

function defer(){ let deferred = {}; deferred.promise = new
Promise((resolve, reject) => { deferred.resolve = resolve
deferred.reject = reject }) return deferred } class Idle { wait(time){
this.deferred = new defer() this.timer = setTimeout(()=>{
this.deferred.resolve({canceled: false}) }, time) return
this.deferred.promise } cancel(){ clearTimeout(this.timer)
this.deferred.resolve({canceled: true}) } } const idleCtrl = new Idle()
async function turnOnTraffic(){ let state; //noprotect do {
traffic.className = ‘stop’ state = await idleCtrl.wait(1000)
if(state.canceled) break traffic.className = ‘pass’ state = await
idleCtrl.wait(1500) if(state.canceled) break traffic.className = ‘wait’
state = await idleCtrl.wait(500) if(state.canceled) break }while(1)
traffic.className = ” } turnOnTraffic() onoffButton.onclick =
function(){ if(traffic.className === ”){ turnOnTraffic()
onoffButton.innerHTML = ‘关闭’ } else { onoffButton.innerHTML = ‘开启’
idleCtrl.cancel() } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
function defer(){
  let deferred = {};
  deferred.promise = new Promise((resolve, reject) => {
    deferred.resolve = resolve
    deferred.reject = reject
  })
  return deferred
}
 
class Idle {
  wait(time){
    this.deferred = new defer()
    this.timer = setTimeout(()=>{
      this.deferred.resolve({canceled: false})
    }, time)
 
    return this.deferred.promise
  }
  cancel(){
    clearTimeout(this.timer)
    this.deferred.resolve({canceled: true})
  }
}
 
const idleCtrl = new Idle()
 
async function turnOnTraffic(){
  let state;
  //noprotect
  do {
    traffic.className = ‘stop’
    state = await idleCtrl.wait(1000)
    if(state.canceled) break
    traffic.className = ‘pass’
    state = await idleCtrl.wait(1500)
    if(state.canceled) break
    traffic.className = ‘wait’
    state = await idleCtrl.wait(500)
    if(state.canceled) break
  }while(1)
  traffic.className = ”
}
 
turnOnTraffic()
 
onoffButton.onclick = function(){
  if(traffic.className === ”){
    turnOnTraffic()
    onoffButton.innerHTML = ‘关闭’
  } else {
    onoffButton.innerHTML = ‘开启’
    idleCtrl.cancel()
  }
}

上面这么做实现了控制交通灯的开启关闭。但是实际上这样的代码让
onoffButton、 idelCtrl 和 traffic 各种耦合,有点惨不忍睹……

这还只是最简单的“开启/关闭”,“暂停/继续”要比这个更复杂,还有用户自己控制灯的切换呢,想想都头大!

在这种情况下,因为我们把控制和状态混合在一起,所以程序逻辑不可避免地复杂了。这种复杂度与
callback 和 async/await 无关。async/await
只能改变程序的结构,并不能改变内在逻辑的复杂性。

那么我们该怎么做呢?这里我们就要换一种思路,让信号(Signal)登场了!看下面的例子:

JS Bin on jsbin.com

class Idle extends Signal { async wait(time){ this.state = ‘wait’ const
timer = setTimeout(() => { this.state = ‘timeout’ }, time) await
this.while(‘wait’) clearTimeout(timer) } cancel(){ this.state = ‘cancel’
} } class TrafficSignal extends Signal { constructor(id){ super(‘off’)
this.container = document.getElementById(id) this.idle = new Idle() }
get lightStat(){ return this.state } async pushStat(val, dur = 0){
this.container.className = val this.state = val await
this.idle.wait(dur) } get canceled(){ return this.idle.state ===
‘cancel’ } cancel(){ this.pushStat(‘off’) this.idle.cancel() } } const
trafficSignal = new TrafficSignal(‘traffic’) async function
turnOnTraffic(){ //noprotect do { await trafficSignal.pushStat(‘stop’,
1000) if(trafficSignal.canceled) break await
trafficSignal.pushStat(‘pass’, 1500) if(trafficSignal.canceled) break
await trafficSignal.pushStat(‘wait’, 500) if(trafficSignal.canceled)
break }while(1) trafficSignal.lightStat = ‘off’ } turnOnTraffic()
onoffButton.onclick = function(){ if(trafficSignal.lightStat === ‘off’){
turnOnTraffic() onoffButton.innerHTML = ‘关闭’ } else {
onoffButton.innerHTML = ‘开启’ trafficSignal.cancel() } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class Idle extends Signal {
  async wait(time){
    this.state = ‘wait’
    const timer = setTimeout(() => {
      this.state = ‘timeout’
    }, time)
    await this.while(‘wait’)
    clearTimeout(timer)
  }
  cancel(){
    this.state = ‘cancel’
  }
}
 
class TrafficSignal extends Signal {
  constructor(id){
    super(‘off’)
    this.container = document.getElementById(id)
    this.idle = new Idle()
  }
  get lightStat(){
    return this.state
  }
  async pushStat(val, dur = 0){
    this.container.className = val
    this.state = val
    await this.idle.wait(dur)
  }
  get canceled(){
    return this.idle.state === ‘cancel’
  }
  cancel(){
    this.pushStat(‘off’)
    this.idle.cancel()
  }
}
 
const trafficSignal = new TrafficSignal(‘traffic’)
 
async function turnOnTraffic(){
  //noprotect
  do {
    await trafficSignal.pushStat(‘stop’, 1000)
    if(trafficSignal.canceled) break
    await trafficSignal.pushStat(‘pass’, 1500)
    if(trafficSignal.canceled) break
    await trafficSignal.pushStat(‘wait’, 500)
    if(trafficSignal.canceled) break
  }while(1)
 
  trafficSignal.lightStat = ‘off’
}
 
 
turnOnTraffic()
 
onoffButton.onclick = function(){
  if(trafficSignal.lightStat === ‘off’){
    turnOnTraffic()
    onoffButton.innerHTML = ‘关闭’
  } else {
    onoffButton.innerHTML = ‘开启’
    trafficSignal.cancel()
  }
}

我们对代码进行一些修改,封装一个 TrafficSignal,让 onoffButton 只控制
traficSignal 的状态。这里我们用一个简单的 Signal
库,它可以实现状态和控制流的分离,例如:

JS Bin on jsbin.com

const signal = new Signal(‘default’) ;(async () => { await
signal.while(‘default’) console.log(‘leave default state’) })() ;(async
() => { await signal.until(‘state1’) console.log(‘to state1’) })()
;(async () => { await signal.until(‘state2’) console.log(‘to state2’)
})() ;(async () => { await signal.until(‘state3’) console.log(‘to
state3’) })() setTimeout(() => { signal.state = ‘state0’ }, 1000)
setTimeout(() => { signal.state = ‘state1’ }, 2000) setTimeout(()
=> { signal.state = ‘state2’ }, 3000) setTimeout(() => {
signal.state = ‘state3’ }, 4000)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const signal = new Signal(‘default’)
 
;(async () => {
    await signal.while(‘default’)
    console.log(‘leave default state’)
})()
 
;(async () => {
    await signal.until(‘state1’)
    console.log(‘to state1’)
})()
 
;(async () => {
    await signal.until(‘state2’)
    console.log(‘to state2’)
})()
 
;(async () => {
    await signal.until(‘state3’)
    console.log(‘to state3’)
})()
 
setTimeout(() => {
    signal.state = ‘state0’
}, 1000)
 
setTimeout(() => {
    signal.state = ‘state1’
}, 2000)
 
setTimeout(() => {
    signal.state = ‘state2’
}, 3000)
 
setTimeout(() => {
    signal.state = ‘state3’
}, 4000)

有同学说,这样写代码也不简单啊,代码量比上面写法还要多。的确这样写代码量是比较多的,但是它结构清晰,耦合度低,可以很容易扩展,比如:

JS Bin on jsbin.com

class Idle extends Signal { async wait(time){ this.state = ‘wait’ const
timer = setTimeout(() => { this.state = ‘timeout’ }, time) await
this.while(‘wait’) clearTimeout(timer) } cancel(){ this.state = ‘cancel’
} } class TrafficSignal extends Signal { constructor(id){ super(‘off’)
this.container = document.getElementById(id) this.idle = new Idle() }
get lightStat(){ return this.state } async pushStat(val, dur = 0){
this.container.className = val this.state = val if(dur) await
this.idle.wait(dur) } get canceled(){ return this.idle.state ===
‘cancel’ } cancel(){ this.idle.cancel() this.pushStat(‘off’) } } const
trafficSignal = new TrafficSignal(‘traffic’) async function
turnOnTraffic(){ //noprotect do { await trafficSignal.pushStat(‘stop’,
1000) if(trafficSignal.canceled) break await
trafficSignal.pushStat(‘pass’, 1500) if(trafficSignal.canceled) break
await trafficSignal.pushStat(‘wait’, 500) if(trafficSignal.canceled)
break }while(1) trafficSignal.lightStat = ‘off’ } turnOnTraffic()
onoffButton.onclick = function(){ if(trafficSignal.lightStat === ‘off’){
turnOnTraffic() onoffButton.innerHTML = ‘关闭’ } else {
onoffButton.innerHTML = ‘开启’ trafficSignal.cancel() } }
turnRed.onclick = function(){ trafficSignal.cancel()
trafficSignal.pushStat(‘stop’) } turnGreen.onclick = function(){
trafficSignal.cancel() trafficSignal.pushStat(‘pass’) }
turnYellow.onclick = function(){ trafficSignal.cancel()
trafficSignal.pushStat(‘wait’) }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class Idle extends Signal {
  async wait(time){
    this.state = ‘wait’
    const timer = setTimeout(() => {
      this.state = ‘timeout’
    }, time)
    await this.while(‘wait’)
    clearTimeout(timer)
  }
  cancel(){
    this.state = ‘cancel’
  }
}
 
class TrafficSignal extends Signal {
  constructor(id){
    super(‘off’)
    this.container = document.getElementById(id)
    this.idle = new Idle()
  }
  get lightStat(){
    return this.state
  }
  async pushStat(val, dur = 0){
    this.container.className = val
    this.state = val
    if(dur) await this.idle.wait(dur)
  }
  get canceled(){
    return this.idle.state === ‘cancel’
  }
  cancel(){
    this.idle.cancel()
    this.pushStat(‘off’)
  }
}
 
const trafficSignal = new TrafficSignal(‘traffic’)
 
async function turnOnTraffic(){
  //noprotect
  do {
    await trafficSignal.pushStat(‘stop’, 1000)
    if(trafficSignal.canceled) break
    await trafficSignal.pushStat(‘pass’, 1500)
    if(trafficSignal.canceled) break
    await trafficSignal.pushStat(‘wait’, 500)
    if(trafficSignal.canceled) break
  }while(1)
 
  trafficSignal.lightStat = ‘off’
}
 
 
turnOnTraffic()
 
onoffButton.onclick = function(){
  if(trafficSignal.lightStat === ‘off’){
    turnOnTraffic()
    onoffButton.innerHTML = ‘关闭’
  } else {
    onoffButton.innerHTML = ‘开启’
    trafficSignal.cancel()
  }
}
 
turnRed.onclick = function(){
  trafficSignal.cancel()
  trafficSignal.pushStat(‘stop’)
}
 
turnGreen.onclick = function(){
  trafficSignal.cancel()
  trafficSignal.pushStat(‘pass’)
}
 
turnYellow.onclick = function(){
  trafficSignal.cancel()
  trafficSignal.pushStat(‘wait’)
}

Signal
非常适合于事件控制的场合,再举一个更简单的例子,如果我们用一个按钮控制简单的动画的暂停和执行,可以这样写:

JS Bin on jsbin.com

let traffic = new Signal(‘stop’) requestAnimationFrame(async function
update(t){ await traffic.until(‘pass’) block.style.left =
parseInt(block.style.left || 50) + 1 + ‘px’
requestAnimationFrame(update) }) button.onclick = e => {
traffic.state = button.className = button.className === ‘stop’ ? ‘pass’
: ‘stop’ }

1
2
3
4
5
6
7
8
9
10
11
let traffic = new Signal(‘stop’)
 
requestAnimationFrame(async function update(t){
  await traffic.until(‘pass’)
  block.style.left = parseInt(block.style.left || 50) + 1 + ‘px’
  requestAnimationFrame(update)
})
 
button.onclick = e => {
  traffic.state = button.className = button.className === ‘stop’ ? ‘pass’ : ‘stop’
}

欲练JS,必先攻CSS——前端修行之路

2018/01/04 · CSS ·
CSS

原文出处: 子慕大诗人   

  今天我讲的主题是css,具体聊一下我大概的css学习历史,分享一些干货,希望这次分享对大家有所启发和帮助。

一、如何在自己的开发环境中支持async/await语法

这里主要介绍两种方式。

总结

我们可以用 Signal
来控制异步流程,它最大的作用是将状态和控制分离,我们只需要改变 Signal
的状态,就可以控制异步流程,Signal 支持 until 和 while
谓词,来控制状态的改变。

可以在 GitHub repo
上进一步了解关于 Signal 的详细信息。

1 赞 收藏
评论

图片 2

个人的css历史:

说说自己的css学习的历史,12年,当时是老师手把手1对1教我div+float的固定布局,所有元素全部用float,做了学生会网站的全部前端页面,因为有段时间学PS比较多,也是自己做的UI,很丑,老师说第一次做成这样很不错了,那时老师就觉得我有做前端的天赋,我就是从这个时候开始接触前端的。毕业设计自己一个人做了一个全栈的web,做完整个毕业设计后,我就决定出来要做前端,感觉自己更喜欢。14年出来工作,那时候还不会用什么less,就是直接写css,那时候主要还是写固定布局的pc页面,14年底自己在项目里折腾,用了一下JQmobile,超级难用。15年做一个移动端项目的时候,调研了几个css库,学习了bootstrap和它部分源码,还用到了webfont,使用流式布局这一次提升很大再后来学习了rem,并用到了项目中,至此我的css就到了一个缓慢成长期,或者说就没有特意学习css了。

1. webpack中支持该语法

首先在当前项目中使用npm下载babel-loader

> npm install babel-loader –save-dev

1
> npm install babel-loader –save-dev

然后在配置文件webpack.confing.dev.js中配置,在module.exports.module.rules中添加如下配置元素即可。

{ test: /\.(js|jsx)$/, include: paths.appSrc, loader:
require.resolve(‘babel-loader’), options: { cacheDirectory: true, }, },

1
2
3
4
5
6
7
8
  {
    test: /\.(js|jsx)$/,
    include: paths.appSrc,
    loader: require.resolve(‘babel-loader’),
    options: {
      cacheDirectory: true,
    },
  },

如果你使用最新版本的create-react-app或者vue-cli来构建你的代码,那么它们应该已经支持了该配置。

干货

下面来说一些,我平时比较注意的细节、技术点,和一些大家可能不是很熟悉的知识点。

2. gulp中支持该语法

首先安装gulp插件

> npm install gulp-babel –save-dev

1
> npm install gulp-babel –save-dev

然后编写任务

var gulp = require(‘gulp’); var babel = require(‘gulp-babel’);
gulp.task(‘babel’, function() { return gulp.src(‘src/app.js’)
.pipe(babel()) .pipe(gulp.dest(‘dist’)); });

1
2
3
4
5
6
7
8
var gulp = require(‘gulp’);
var babel = require(‘gulp-babel’);
 
gulp.task(‘babel’, function() {
  return gulp.src(‘src/app.js’)
    .pipe(babel())
    .pipe(gulp.dest(‘dist’));
});

1.box-sizing: border-box

box-sizing主要有两个值content-box和border-box,先看下官方的解释:图片 3

 

通俗一点来说,默认情况下,padding和border是会额外占据空间的,假如元素宽是10px,如果设置了1px
border边框,实际的宽就是12px,padding同理。那么这样会导致,布局的宽高不好控制,计算也特别麻烦。所以我们会给全局的元素用上border-box,
只要设置了宽高,那么border和padding无论怎么变化,元素的宽高都不会变,这样方便布局和计算。

图片 4

二、如何使用

async函数是Generator的一个语法糖。如果你不知道Generator是什么函数也没有关系,我们只需要知道async函数实际上返回的是一个Promise对象即可。

async function fn() { return 30; } // 或者 const fn = async () => {
return 30; }

1
2
3
4
5
6
7
8
async function fn() {
    return 30;
}
 
// 或者
const fn = async () => {
    return 30;
}

在声明函数时,前面加上关键字async,这就是async的用法。当我们用console.log打印出上面声明的函数fn,我们可以看到如下结果:

console.log(fn()); // result Promise = { __proto__: Promise,
[[PromiseStatus]]: “resolved”, [[PromiseValue]]: 30 }

1
2
3
4
5
6
7
8
console.log(fn());
 
// result
Promise = {
    __proto__: Promise,
    [[PromiseStatus]]: "resolved",
    [[PromiseValue]]: 30
}

很显然,fn的运行结果其实就是一个Promise对象。因此我们也可以使用then来处理后续逻辑。

fn().then(res => { console.log(res); // 30 })

1
2
3
fn().then(res => {
    console.log(res);  // 30
})

await的含义为等待。意思就是代码需要等待await后面的函数运行完并且有了返回结果之后,才继续执行下面的代码。这正是同步的效果。

但是我们需要注意的是,await关键字只能在async函数中使用。并且await后面的函数运行后必须返回一个Promise对象才能实现同步的效果。

当我们使用一个变量去接收await的返回值时,该返回值为Promise中resolve出来的值。

// 定义一个返回Promise对象的函数 function fn() { return new
Promise((resolve, reject) => { setTimeout(() => { resolve(30); },
1000); }) } // 然后利用async/await来完成代码 const foo = async () =>
{ const t = await fn(); console.log(t); console.log(‘next code’); }
foo(); // result: // 30 // next code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 定义一个返回Promise对象的函数
function fn() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(30);
        }, 1000);
    })
}
 
// 然后利用async/await来完成代码
const foo = async () => {
    const t = await fn();
    console.log(t);
    console.log(‘next code’);
}
 
foo();
 
// result:
// 30
// next code

运行这个例子我们可以看出,当在async函数中,运行遇到await时,就会等待await后面的函数运行完毕,而不会直接执行next code

如果我们直接使用then方法的话,想要达到同样的结果,就不得不把后续的逻辑写在then方法中。

const foo = () => { return fn().then(t => { console.log(t);
console.log(‘next code’); }) } foo();

1
2
3
4
5
6
7
8
const foo = () => {
    return fn().then(t => {
        console.log(t);
        console.log(‘next code’);    
    })
}
 
foo();

很显然如果使用async/await的话,代码结构会更加简洁,逻辑也更加清晰。

2.左边固定 右边自适应

在布局的时候,比如一些列表页,常常左边是一个固定大小的缩略图,右边剩余部分展示标题,如图

图片 5

那我们就叫左边固定右边自适应的布局吧,我的方法
100%宽的div用padding-left把左边图片的位置留出来,div元素内容的部分就是标题,图片绝对定位到padding-left区域,这样就实现了左固定右自适应,(前提是box-sizing必须是border-box,否则padding加上100%宽会超出屏幕宽度),大致代码如下:

图片 6

异常处理

在Promise中,我们知道是通过catch的方式来捕获异常。而当我们使用async时,则通过try/catch来捕获异常。

function fn() { return new Promise((resolve, reject) => {
setTimeout(() => { reject(‘some error.’); }, 1000); }) } const foo =
async () => { try { await fn(); } catch (e) { console.log(e); // some
error } } foo();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function fn() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(‘some error.’);
        }, 1000);
    })
}
 
const foo = async () => {
    try {
        await fn();
    } catch (e) {
        console.log(e);  // some error
    }
}
 
foo();

如果有多个await函数,那么只会返回第一个捕获到的异常。

function fn1() { return new Promise((resolve, reject) => {
setTimeout(() => { reject(‘some error fn1.’); }, 1000); }) } function
fn2() { return new Promise((resolve, reject) => { setTimeout(() =>
{ reject(‘some error fn2.’); }, 1000); }) } const foo = async () => {
try { await fn1(); await fn2(); } catch (e) { console.log(e); // some
error fn1. } } foo();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function fn1() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(‘some error fn1.’);
        }, 1000);
    })
}
function fn2() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(‘some error fn2.’);
        }, 1000);
    })
}
 
const foo = async () => {
    try {
        await fn1();
        await fn2();
    } catch (e) {
        console.log(e);  // some error fn1.
    }
}
 
foo();

3.伪类的 content attr

伪类before,after的content属性,是用来插入内容的,我们可以通过attr
传入一个当前元素的属性名,把属性值,载入进伪类内容,这个是一种写法,但实际应用场景可能并不多,就当了解一下吧

图片 7

实践

在实践中我们遇到异步场景最多的就是接口请求,那么这里就以jquery中的$.get为例简单展示一下如何配合async/await来解决这个场景。

//
先定义接口请求的方法,由于jquery封装的几个请求方法都是返回Promise实例,因此可以直接使用await函数实现同步
const getUserInfo = () => $.get(‘xxxx/api/xx’); const clickHandler =
async () => { try { const resp = await getUserInfo(); //
resp为接口返回内容,接下来利用它来处理对应的逻辑 console.log(resp); //
do something } catch (e) { // 处理错误逻辑 } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 先定义接口请求的方法,由于jquery封装的几个请求方法都是返回Promise实例,因此可以直接使用await函数实现同步
const getUserInfo = () => $.get(‘xxxx/api/xx’);
 
const clickHandler = async () => {
    try {
        const resp = await getUserInfo();
        // resp为接口返回内容,接下来利用它来处理对应的逻辑
        console.log(resp);
 
        // do something
    } catch (e) {
        // 处理错误逻辑
    }
}

为了保证逻辑的完整性,在实践中try/catch必不可少。总之,不处理错误逻辑的程序员不是好程序员。

与Promise相比,个人认为async/await有一定的简洁性,但也并非就比Promise有绝对的优势,因此只能算是提供了另外一种稍好的方式,至于大家学习之后选择哪种方式来解决自己的问题,这仅仅只是你的个人喜好问题。

1 赞 3 收藏
评论

图片 2

4.中文符号居中效果

对于动态输出文字可以不用在意,某些页面可能会有类似提示文案的地方,用英文标点符号,对于居中效果比较友好。

图片 9

发表评论

电子邮件地址不会被公开。 必填项已用*标注