background

Recently, I contacted a UMI project, in which DVA is used for state management. Then you find generator syntax for JS. Although I’ve worked with generators in other languages (Python, PHP) before, I know what they do. But for asynchronous programming in JS synchronous writing method is not quite clear behind the principle, so studied.

process

First we define an asynchronous method to get the data, call it and return a Promise object, then we do not use async/await, use generator to copy DVA writing and write synchronous code to get the data.

const fetchData = () = > new Promise(resolve= > {
    setTimeout(() = > {
        resolve('test data')},3000)})function *test(call) {
    const res = yield call(fetchData)
    console.log(res)
}
Copy the code

We know that once we call generator’s next method, the program goes one step further. So how do we write the call parameter so that we can call next when appropriate?

I came up with my own idea here

const call = p= > {
    p.then(res= > {
        g.next(res)
    })
}

g = test(call)
g.next()
Copy the code

The final code, plus the log print, looks at the order of execution:

const fetchData = () = > new Promise(resolve= > {
    setTimeout(() = > {
        resolve('test data')},3000)})function *test(call) {
    console.log(2)
    const res = yield call(fetchData())
    console.log(res)
}

const call = p= > {
    console.log(3)
    p.then(res= > {
        console.log(4)
        g.next(res);
        console.log(5)});console.log(6)}console.log(-1)
g = test(call)
console.log(0)
g.next()
console.log(1)
Copy the code

The execution result

-1
0
2
3
6
1
4
test data
5
Copy the code

This allows us to emulate async/await using generator.

further

Here we pass a call again, which is ugly and can only execute a single yield generator. So revamp it a bit and introduce a run method that uses recursion to automatically go down, like this:

const fetchData = (arg) = > new Promise(resolve= > {
    setTimeout(() = > {
        resolve('test data ' + arg)
    }, 3000)})function *test() {
    console.log('0')
    let res = yield fetchData('1')
    console.log('1', res)
    res = yield fetchData(res)
    console.log('2', res)
    res = yield fetchData(res)
    console.log('3', res)
    res = yield fetchData(res)
    console.log('4', res)
}

const run = g= > {
    const next = val= > {
        const res = g.next(val)
        if(res.done) return res.value
        res.value.then(next)
    }

    next()
}

run(test())
Copy the code

The execution result

0
1 test data 1
2 test data test data 1
3 test data test data test data 1
4 test data test data test data test data 1
Copy the code

reference

  1. Developer.mozilla.org/zh-CN/docs/…