手写之前先学习下async/await

async

async 函数是什么?一句话,它就是 Generator 函数的语法糖。
异步的简写,用于申明一个函数是异步的,而await用于等待一个异步方法执行完成,await只能出现在async函数中。

1
2
3
4
5
6
7
8
9
10
11
12
var getData = () => new Promise(resolve => setTimeout(() => resolve('data'), 3000))
async function test() {
const data = await getData()
console.log('data: ', data);
const data2 = await getData()
console.log('data2: ', data2);
return 'success'
}
test().then(res => console.log(res))
// data: data
// data2: data
// success

换成generator函数就是

1
2
3
4
5
6
7
function* test() {
const data = yield getData()
console.log('data: ', data);
const data2 = yield getData()
console.log('data2: ', data2);
return 'success'
}

async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。

async函数对 Generator 函数的改进,体现在以下四点。

  • 内置执行器。
    Generator函数的执行必须靠执行器,而async函数自带执行器,不许再跳用next方法
  • 更好的语义
    async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
  • 更广的适用性
    yield/await
  • 返回值是 Promise
    async返回的是Promise,你阔以用then指定下一步操作。而Generator返回的是Iterator迭代器对象。
    async函数完全能理解成多个异步操作,包装成一个Promise对象, async函数是Generator函数的语法糖,而await命令就是内部的then命令的语法糖
    总的解释就是:
    async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

    手写async(单说async)

    1
    2
    3
    4
    5
    6
    7
    async function foo() {
    return 1
    }
    // 相当于
    function foo() {
    return Promise.resolve(1)
    }
    模拟实现async
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    async function foo() {
    console.log('foo function')
    return 1
    }
    var data = foo()
    data.then(res => console.log(res))

    // 模拟async
    function _async(fn) {
    return (...args) => Promise.resolve(fn(...args))
    }
    function foo() {
    console.log('foo function')
    return 1
    }
    var data = _async(foo)()
    data.then(res => console.log(res))
    console.log('data')
    // foo function
    // data
    // 1

async/await

await使用场景

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
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(m, n) {
console.log(`step2 with ${m} and ${n}`);
return takeLongTime(m + n);
}
function step3(k, m, n) {
console.log(`step3 with ${k}, ${m} and ${n}`);
return takeLongTime(k + m + n);
}

async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time1, time2);
const result = await step3(time1, time2, time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}

如果用Promise如何实现1

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

function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(m, n) {
console.log(`step2 with ${m} and ${n}`);
return takeLongTime(m + n);
}
function step3(k, m, n) {
console.log(`step3 with ${k}, ${m} and ${n}`);
return takeLongTime(k + m + n);
}

function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then((time2) => {
return step2(time1, time2).then(
time3 => [time1, time2,time3]
)
})
.then((rest) => {
const [time1, time2, time3] = rest
return step3(time1, time2, time3)
})
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
})
}

Promise解法二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1).then((res1) => {
const time2 = res1;
step2(time1, time2).then((res2) => {
const time3 = res2;
step3(time1, time2, time3).then((res3) => {
console.log(`result is ${res3}`);
console.timeEnd("doIt");
})
})
})
}

doIt();

注意:

await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try…catch 代码块中,或者await后的Promise添加catch回调

1
2
3
4
await read('1.txt','utf8')
.catch(function(err){
console.log(err);
})

手写 await

如果是手动执行里面的执行器,则需要这么实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var getData = () => new Promise(resolve => setTimeout(() => resolve('data'), 3000))
console.log(getData(), 'getData')
function* testG() {
var data = yield getData()
console.log('data1', data)
var data2 = yield getData()
console.log('data2',data2)
return 'success'
}
var gg = testG()
var dataPromise = gg.next()
dataPromise.value.then((val1) => {
var data2proimse = gg.next(val1);
console.log(data2proimse, 'data2proimse')
data2proimse.value.then((val2) => {
var data3 = gg.next(val2);
gg.next()
console.log(data3, 'da ta3')
})
})

大神版模拟async/await

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
var getData = () => new Promise(resolve => setTimeout(() => resolve('data'), 3000))
console.log(getData(), 'getData')
function asyncToGenerator(generatorFunc) {
return function() {
const gen = generatorFunc.apply(this, arguments)
return new Promise((resolve, reject) => {
function step(key, arg) {
let generatorResult
try {
generatorResult = gen[key](arg)
} catch (error) {
return reject(error)
}
const { value, done } = generatorResult
if (done) {
return resolve(value)
} else {
return Promise.resolve(value).then(
val => step('next', val),
err => step('throw', err))
}
}
step("next")
})
}
}
var gg = asyncToGenerator(
function* testG() {
var data = yield getData()
console.log('data1', data)
var data2 = yield getData()
console.log('data2',data2)
return 'success'
}
)
gg().then(res => console.log(res, 'res'))

参考链接