Talk about asynchronous programming from js

The purpose of the article

Unveil the mystery of gorouter of go, async/await of c#writing asynchronous code in synchronous writing, and prove that it is essentially a grammatical sugar

Why use js for asynchronous programming

Because js can implement async/await syntax through the programming language's own syntax features

js asynchronous bottom-most write promise

const promise = new Promise(function(resolve, reject) {
  xxxxx.asynchronous IO operation((res)=>{
      if(res Success){
          resolve(res)
      }else{
          reject(res)
      }
  })
});

The callback function of promise in and out has certain requirements

  • The resolve function changes the state of the Promise object from incomplete to successful (that is, from pending to resolved), calls when the asynchronous operation succeeds, and passes the result of the asynchronous operation as a parameter
  • The reject function changes the state of the Promise object from incomplete to failed (that is, from pending to rejected), calls when an asynchronous operation fails, and passes the error reported by the asynchronous operation as a parameter.

After the Promise instance is generated, you can use the then method to specify the callback functions for the resolved and rejected states, respectively (to process the returned results).

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

Extension-Note: The promise object is very special in js, such as the following example

const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => reject(new Error('fail')), 3000)
})

const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => resolve(p1), 1000)
})
p2
  .then(result => console.log(result))
  .catch(error => console.log(error))

This result is failt because resolve in p2 returns a promise object, which will result in the state of p2 being upgraded to the state of p1 (standard)

The n-Chain Writing of promise

The promise then method will return a promise, so js supports chain asynchronization

var getJSON = function (url, callback) {
    var promise = new Promise(function (resolve, reject) {
        var client = new XMLHttpRequest();
        client.open("GET", url);
        client.onreadystatechange = handler;//The readystatechange event is triggered when the value of the readyState property changes from one value to another
        client.responseType = "json";
        client.setRequestHeader("Accept", "application/json");
        client.send();

        function handler() {
            if (this.readyState !== 4) {
                return;
            }
            if (this.status === 200) {
                callback(this.response);
                resolve(this.response);
            } else {
                reject(new Error(this.statusText))
            }
        };
    });
    return promise;
};
getJSON("./e2e-tests/get.json", function (resp) {
    console.log("get:" + resp.name);
}).then(function (json) {
    getJSON("./e2e-tests/get2.json", function (resp) {
        console.log("get2:" + resp.name);
    })
}).catch(function (error) {
    console.log("error1: " + error);
});

promise exception capture

p.then((val) => console.log('fulfilled:', val))
  .catch((err) => console.log('rejected', err));

// Equivalent to
p.then((val) => console.log('fulfilled:', val))
  .then(null, (err) => console.log("rejected:", err));

This exception capture is the same as java, capturing exceptions generated in eventLoop

Note that this exception is different from java's try catch and will not appear in the main thread if an exception is generated

finally of promise

This is the same exception system as java, finally independent state, and will execute eventually

Promise.resolve(2).finally(() => {})

More convenient writing for asynchronous use of Promise.resolve(xxx)

Promise.resolve('foo')
// Equivalent to
new Promise(resolve => resolve('foo'))

Note: promise asynchronization results can only be obtained in callback functions, if too many asynchronous operations are performed, the call link will be tuned to be too long

How to solve the problem of promise asynchronous programming for js?

What's wrong with promise writing? - - The call link is too long

For example, use promise to implement asynchronous ajax requests

var getJSON = function (url, callback) {
    var promise = new Promise(function (resolve, reject) {
        var client = new XMLHttpRequest();
        client.open("GET", url);
        client.onreadystatechange = handler;//The readystatechange event is triggered when the value of the readyState property changes from one value to another
        client.responseType = "json";
        client.setRequestHeader("Accept", "application/json");
        client.send();
        function handler() {
            if (this.readyState !== 4) {
                return;
            }
            if (this.status === 200) {
                callback(this.response);
                resolve(this.response);
            } else {
                reject(new Error(this.statusText))
            }
        };
    });
    return promise;
};
getJSON("./e2e-tests/get.json", function (resp) {
    console.log("get:" + resp.name);
}).then(function (json) {
    getJSON("./e2e-tests/get2.json", function (resp) {
        console.log("get2:" + resp.name);
    })
}).catch(function (error) {
    console.log("error1: " + error);
});

Call chain too long, non-stop promise calls

How js Solves Callback Hell - Synchronous Method Write Asynchronous

Solution uses js protocol--Generator

Special syntax for generator:js, which uses the yield keyword to block functions, and then manually controls execution using traversers

Example:

function * gen(){
    let a= 123;
    let b = yield a;
    let c = yield a+b;
    return a+b+c;
}

let start = gen();

console.log(start.next());
console.log(start.next(2));
console.log(start.next(3));

Essentially a function slice

js gets the expression of the current position each time yield ed, and then manually embeds it to achieve the effect of slicing control

How to use generator for asynchronization--yield with promise for asynchronization

Take a look at this method

function* asyncFn(value) {
    let a = yield promiseOne(value);
    let b = yield promiseTwo(a);
    return a + b;
}

To allow him to execute asynchronously, simply let the result of the previous promise be the input to the next promise

There are two ways to write

how to write

Recursive equation: f (final result) = f (present result) +f (next result)

function promiseOne(xxx) {
    return new Promise((res, rej) => {
        res(xxx + 1);
    })
}
function promiseTwo(xxx) {
    return new Promise((res, rej) => {
        res(xxx + 1);
    })
}
function* asyncFn(value) {
    let a = yield promiseOne(value);
    let b = yield promiseTwo(a);
    return a + b;
}
function runAsync(fn,value) {
    let item = fn.next(value);
    return new Promise((res, rej) => {
        if (!item.done) {
            if (item.value instanceof Promise) {
                item.value.then((re)=>{
                    runAsync(fn,re).then(res);
                })
            } else {
                runAsync(fn,fn.valueOf()).then(res);
            }
        } else {
            res(item.value);//This res method is really everyone's res method
        }
    })
}
runAsync(asyncFn(12)).then(res=>{
    console.log(res);
});

Writing of the co Toolkit

function run (gen) {
  gen = gen()
  return next(gen.next())
  function next ({done, value}) {
    return new Promise(resolve => {
     if (done) { // finish
       resolve(value)
     } else { // not yet
       value.then(data => {
         next(gen.next(data)).then(resolve)
       })
     }
   })
  }
}
function getRandom () {
  return new Promise(resolve => {
    setTimeout(_ => resolve(Math.random() * 10 | 0), 1000)
  })
}
function * main () {
  let num1 = yield getRandom()
  let num2 = yield getRandom()
 
  return num1 + num2
}
run(main).then(data => {
  console.log(`got data: ${data}`);
})

Writing Two

Recursive equation f (final result) = f (all previous results) +f (result of last step)

//Synchronous Write Asynchronous
function asyncRun(resf, fn, value) {
    let a = fn(value);
    go(value);
    function go(value) {
        let next = a.next(value);
        if (!next.done) {
            if (next.value instanceof Promise) {
                next.value.then((res) => {
                    go(res);
                });
            } else {
                return go(next.value);
            }
        } else {
            resf(next.value);
        }
    }
}
function* asyncFn(value) {
    let a = yield promiseOne(value);
    let b = yield promiseTwo(a);
    return a + b;
}
function show(item) {
    console.log(item)
}
asyncRun(show, asyncFn, 12);
function promiseOne(xxx) {
    return new Promise((res, rej) => {
        res(xxx + 1);
    })
}
function promiseTwo(xxx) {
    return new Promise((res, rej) => {
        res(xxx + 1);
    })
}

Simpler method async/await

What if the above complex code becomes async/await?

It's simple

// function* asyncFn(value) {
//     let a = yield promiseOne(value);
//     let b = yield promiseTwo(a);
//     return a + b;
// }
function promiseOne(xxx) {
    return new Promise((res, rej) => {
        res(xxx + 1);
    })
}
function promiseTwo(xxx) {
    return new Promise((res, rej) => {
        res(xxx + 1);
    })
}
async function asyncFn(value) {
    let a = await promiseOne(value);
    let b = await promiseTwo(a);
    return a + b;
}
asyncFn(12).then((res)=>{
    console.log(res)
});

From the example above, we can see that async/await is actually a grammatical sugar of generator in essence

await is yield, async's function is to program function grammar sugar

If you do, answer the two rules very briefly:

  1. await must be followed by a promise function
  2. async token promise returned after function execution

Asynchronization can be easily achieved in this way

Keywords: Javascript JSON Programming Java

Added by frijole on Thu, 30 May 2019 19:15:23 +0300