JS 异步发展流程(回调函数=>Async/await)

栏目: JavaScript · 发布时间: 5年前

内容简介:异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。 异步执行的运行机制如下:当然回调函数也有它的缺点:

异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。 异步执行的运行机制如下:

  1. 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
  2. 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
  3. 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
  4. 主线程不断重复上面的第三步。

1、 回调函数

场景: 读取一个文件

let fs = require('fs')
fs.readFile('./1.txt', 'utf8', function(err, data){
    // 回调的特点是第一个参数一般为错误对象
    if (err) { 
        // 如果err有值说明程序出错了
        console.log(err)
    } else { 
        // 否则表示成功获取到数据data
        console.log(data)
    }
})
复制代码

当然回调函数也有它的缺点:

  • 无法捕获错误(使用try catch)
funnction readFile (fileName) {
    fs.readFile(fileName, 'utf8', function (data) {
        if (err) {
            console.log(err)
        } else {
            console.log(data)
        }
    })
}
try {
    readFile('./1.txt')
} catch (e) { 
    // 如果上边读取文件出错,获取不到错误信息
    console.log('err', e)
}
复制代码
readFile 方法中无法返回读取到文件的内容(data)
fs.readFile('./data1.txt', 'utf8', function (err, data1) {
  fs.readFile('./data2.txt', 'utf8', function (err, data2) {
    fs.readFile('./data3.txt', 'utf8', function (err, data3) {
      fs.readFile('./data4.txt', 'utf8', function (err, data4) {
        fs.readFile('./data5.txt', 'utf8', function (err, data5) {
            console.log(data1, data2, data3, data4, data5)
        })
      })
    })
  })
})
// 这样的代码称为恶魔金字塔;且有以下问题
// 1、代码非常难看
// 2、难以维护
// 3、效率比较低,因为它们是串行的;一次只能请求一个文件
复制代码

2、事件发布订阅

为了解决回调嵌套的问题

let EventEmitter = require('events')
// nodejs核心模块之一,包含两个核心方法: 
// on >> 表示注册监听,emit >> 表示发射事件

let eve = new EventEmitter()
let html = {} // 存放页面模板和数据
eve.on('reading', function (key, value) {
    html[key] = value
    if (Object.keys(html).length == 2) {
        console.log(html)
    }
})
fs.readFile('./template.txt', 'utf8', function (err, template) {
    eve.emit('reading', template) 
    // 触发reading事件,执行事件的回调函数向html中填入模板
})
fs.readFile('./data.txt', 'utf8', function (err, template) {
    eve.emit('reading', template) 
    // 触发reading事件,执行事件的回调函数向html中填入数据
})
复制代码

3、哨兵变量

事件发布订阅已经可以解决回调嵌套的问题,但是还需要引入events模块; 利用哨兵变量一样可以解决回调嵌套的问题,且不需要引入其他模块

// 定义一个哨兵函数来处理
function done (key, value) {
    html[key] = value
    if (Object.keys(html).length == 2) {
        console.log(html)
    }
}

fs.readFile('./template.txt', 'utf8', function (err, template) {
    done('template', template)
})
fs.readFile('./data.txt', 'utf8', function (err, template) {
    done('data', data)
})

// 可以封装一个高阶函数去生成哨兵函数
function render (length, cb) {
    let htm = {}
    return function (key, value) {
        html[key] = value
        if (Object.keys(html).length == length) {
            cb(html)
        }
    }
}

let done = render(2, function (html) {
    console.log(html)
})
复制代码

4、Promise

上述方法都是用回调函数来处理异步;我们的目标是把异步往同步的方向靠拢

//promise的用法不再阐述,可自行查阅文档
let promise1 = new Promise(function (resolve, reject) {
    fs.readFile('./1.txt', 'utf8', function (err, data) {
        resolve(data)
    })
})

promise1.then(function (data) {
    console.log(data)
})
复制代码

5、Generator(生成器)

当我们在调用一个函数的时候,它并不会马上执行,而是需要我们手动的去执行迭代操作(next方法);简单来说,调用生成器函数会返回一个迭代器,可以用迭代器来执行遍历每个中断点(yield) 调用next方法会有返回值value,是生成器函数对外输出的数据;next方法还可以接受参数,是向生成器函数内部输入的数据

  • 生成器简单使用
// 方法名前边加*就是生成器函数
function *foo () {
  var index = 0;
  while (index < 2) {
    yield index++; //暂停函数执行,并执行yield后的操作
  }
}
var bar =  foo(); // 返回的其实是一个迭代器

console.log(bar.next());    // { value: 0, done: false }
console.log(bar.next());    // { value: 1, done: false }
console.log(bar.next());    // { value: undefined, done: true }
复制代码
  • 生成器 + Promise解决异步的实现
function readFile (filaName) {
    return new Promise(function (resolve, reject) {
        fs.readFile(filename, function (err, data) {
          if (err) {
            reject(err)
          } else {
            resolve(data)
          }
    })
}
function *read() {
    let template = yield readFile('./template.txt')
    let data = yield readFile('./data.txt')
    return {
        template: template,
        data: data
    }
}
// 生成迭代器r1
let r1 = read()
let templatePromise = r1.next().value
templatePromise.then(function(template) {
    // 将获取到的template的内容传递给生成器函数
    let dataPromsie = r1.next(template).value
    dataPromise.then(function(data) {
        //最后一次执行next传入data的值;最后返回{template, data}
        let result = r1.next(data).value
        console.log(result)
    })
})
复制代码
  • 生成器 + promise的实现已经有了一些同步的样子;借助一些工具(co),可以优雅的编写上述的代码
//实现 co 方法
//参数是一个生成器函数
function co (genFn) {
    let r1 = genFn()
    return new Promise(function(resolev, reject) {
        !function next(lastVal) {
            let p1 = r1.next(lastVal)
            if (p1.done) {
                resolve(p1.value)
            } else {
                p1.value.then(next, reject)
            }
        }()
    })
}

//现在获取上边的result可以这样来取
co(read).then(function(result) {
    console.log(result)
})
复制代码

6、Async/await

Async其实是一个语法糖,它的实现就是将Generator函数和自动执行器(co),包装在一个函数中

//实现 co 方法
//参数是一个生成器函数
async function read() {
  let template = await readFile('./template.txt');
  let data = await readFile('./data.txt');
  return template + '+' + data;
}

// 等同于
function read(){
  return co(function*() {
    let template = yield readFile('./template.txt');
    let data = yield readFile('./data.txt');
    return template + '+' + data;
  });
}
复制代码

异步编程发展的目标就是让异步逻辑的代码看起来像同步一样,发展到Async/await,是处理异步编程的一个里程碑。

特此感谢: PandaShen 、 seventhMa


以上所述就是小编给大家介绍的《JS 异步发展流程(回调函数=>Async/await)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Essential PHP Security

Essential PHP Security

Chris Shiflett / O'Reilly Media / 2005-10-13 / USD 29.95

Being highly flexible in building dynamic, database-driven web applications makes the PHP programming language one of the most popular web development tools in use today. It also works beautifully wit......一起来看看 《Essential PHP Security》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

html转js在线工具
html转js在线工具

html转js在线工具