Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

处理异步问题的方法 #15

Open
Genluo opened this issue Aug 31, 2019 · 0 comments
Open

处理异步问题的方法 #15

Genluo opened this issue Aug 31, 2019 · 0 comments

Comments

@Genluo
Copy link
Owner

Genluo commented Aug 31, 2019

解决异步问题,一种是通过自己编码的注意,通过将功能抽离,然后写成回调函数的形式,另一种就是实现ES6提供的API进行处理,这里我们学习下Generator函数,使用迭代器结合回调函数或者Promise来处理相关异步流程,这也就是async、await等的原理,可以让异步流程更加友好。

  • 普通处理
function asyncFlow(generatorFunction) {
    const generator = generatorFunction(callback)
    function callback(err, ...params) {
        if(err) {
            return generator.throw(err);
        }
        // 单个参数传回值,多个传回对象
        generator.next(params.length > 1 ? params[0] : params);
    }
    generator.next();
}

const fs = require('fs');
const path = require('path');
// 使用方法如下
asyncFlow(function *(callback) {
    const fileName = path.resolve('./index.md');
    const data = yield fs.readFile(fileName, 'utf8', callback);
    yield fs.writeFile('clone_md.md', data, callback);
    console.log('clone over')
})

这个方法可以让我们线性的方法编写异步的代码,背后的魔法就是: 传递给每个异步函数的回调函数将会在异步操作完成后依次恢复generator。自动控制 Generator函数的流程,接收和交还程序的执行权。回调函数可以做到这一点,Promise 对象也可以做到这一点。

  • thunk变体
const fs = require('fs');
const path = require('path');

function readFileThunk(fileName, options) {
    return function (callback) {
        let called = false;
        function _call(...params) {
            if(called) return;
            callback(...params);
        }
        fs.readFile(fileName, options, _call);
    }
}

function writeFileThunk(fileName, data) {
    return function(callback) {
        let called = false;
        function _call(...params) {
            if(called) return;
            callback(...params);
        }
        fs.writeFile(fileName, data, _call)
    }
}

function asyncFlow(generatorFunction) {
    const generator = generatorFunction();
    function callback(err, ...params) {
        if (err) return generator.throw(err);
        const thunk = generator.next(params.length > 1 ? params : params[0]).value;
        thunk && thunk(callback);
    }
    const thunk = generator.next().value;
    thunk && thunk(callback);
}

asyncFlow(function *(callback) {
    const fileName = path.resolve('./index.md');
    const data = yield readFileThunk(fileName, 'utf8');
    yield writeFileThunk('clone_md.md', data);
    console.log('clone over')
})
  • Promise变体
const fs = require('fs');
const path = require('path');

function promiseify(fun) {
    return function(...params) {
        return new Promise((resolve, reject) => {
            // 一种写法
            fun(...params, (err, ...args) => {
                if(err) return reject(err);
                resolve(...args);
            });
        })
    }
}

const readFilePromise = promiseify(fs.readFile);
const writeFilePromise = promiseify(fs.writeFile);

function asyncFlow(generatorFunction) {
    const generator = generatorFunction();
    // 出现错误的回调
    function error(err) {
        generator.throw(err);
    }
    // 成功执行的回调
    function callback(params) {
        const promise = generator.next(params).value;
        promise && promise.then(callback).catch(error)
    }
    const promise = generator.next().value;
    promise.then(callback).catch(error)
}

asyncFlow(function *(callback) {
    const fileName = path.resolve('./index.md');
    const data = yield readFilePromise(fileName, 'utf8');
    yield writeFilePromise('clone_md.md', data);
    console.log('clone over')
})
  • co实现的generator控制流
    • Thunk函数
    • Promise
    • Array(并行执行)
    • Object(并行执行)
    • Generator(委托)
    • Generator function(委托)
  • 使用ES6中封装好好的 Async 函数
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant