关于js回调和promise,async/await的理解

关于js,promise,async/await的理解

1、js

const a = function() {
  setTimeout(function() {
    console.log(1)
  }, 2000)
}
a()
console.log(2)
//执行结果:
2
1
复制代码

setTimeout模拟异步回调函数,假设一个回调函数须要2秒猜返回结果。能够看到a函数调用时,并无立马打印出结果就执行下一行打印语句了。
js是单线程的,是从上至下执行语句的,为了避免阻塞语句执行,就有回调机制。回调至关于注册了一个事件池,回调函数注册到这个池子里,在这个池子里去执行回调函数本身的逻辑,有返回结果后才传回给主线程。 下面这个node链接数据库,返回查询结果undefined,也是这个问题。javascript

var mysql = require('mysql');
const mysql = function() {
    console.log('链接的database是', database)
    const url = {
        host     : 'localhost',
        user     : 'root',
        password : '123456',
        database : 'test'
    }
    var connection = mysql.createConnection(url);
       
    connection.connect();
    var mysqlQuery = function(callback) {
        var  sql = 'SELECT * FROM test1'
        connection.query(sql,function(err,result){
            if(err){console.log(err)}
            callback(result)
        })  
    }
    const result = mysqlQuery(function(data) {
        return data
    })
    console.log(result)
    console.log(2)
}
mysql()
// 在console.log(result)时会获取不到结果
复制代码

2、promise

promise 简单理解就promise状态变化的回调函数放到then和catch里,(也能够都放在then里面)约定好成功就执行then里面的函数,失败就执行catch里面的函数。就能够按咱们但愿的去执行哪一个回调,很容易控制执行的顺序。
详细说法promise构造函数接受两个参数,分别是resolve和reject函数,resolve函数的做用是把promise对象的状态从pending变成resolved(未完成到完成),reject函数做用是把promise对象的状态从pending变成reject(未完成到失败)。状态改变后的回调函数分别定义在then里面。java

//实例化promise对象,至于这个promise对象的构造函数什么样不用管,javascript引擎提供了
const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操做成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});
//Promise实例生成之后,能够用then方法分别指定resolved状态和rejected状态的回调函数。
promise.then(function(value) {
  // success
}, function(error) {
  // failure
})
复制代码

promise实例建立后,状态改变后的回调函数要将在当前脚本全部同步任务执行完才会执行。node

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved`
复制代码

上面代码中,Promise 新建后当即执行,因此首先输出的是Promise。而后,then方法指定的回调函数,将在当前脚本全部同步任务执行完才会执行,因此resolved最后输出。mysql

3、ansyc/await

Async

先从async关键字提及,它被放置在一个函数前面。就像下面这样:sql

async function f() {
    return 1
} 
复制代码

函数前面的async一词意味着一个简单的事情:这个函数老是返回一个promise,若是代码中有return <非promise>语句,JavaScript会自动把返回的这个value值包装成promise的resolved值。因此调用这个函数时后面.then(reslove)获取return的值数据库

async function f() {
    return 1
}
f().then(alert) // 1
复制代码

能够显式的返回一个promise,这个将会是一样的结果:json

async function f() {
    return Promise.resolve(1)
}
f().then(alert) // 1
复制代码
Await
// 只能在async函数内部使用
let value = await promise
复制代码

关键词await可让JavaScript进行等待,直到一个promise执行并返回它的结果,JavaScript才会继续往下执行。
例子:segmentfault

async function f() {
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => resolve('done!'), 1000)
    })
    let result = await promise // 直到promise返回一个resolve值(*)
    alert(result) // 'done!' 
}
f()

复制代码

函数执行到(*)行会‘暂停’,当promise处理完成后从新恢复运行,上面await会把promise执行的结果返回,赋值给了result, resolve的值成了最终的result,因此上面的代码会在1s后输出'done!'。
await是一个更优雅的获得promise值的语句,它比promise更加容易阅读和书写。
也就是把promise的.then替换为await数组

  • await不能工做在顶级做用域
let response = await fetch('/article/promise-chaining/user.json')
let user = await response.json()
因此咱们须要将await代码包裹在一个async函数中,就像上面的例子同样。
复制代码
  • 一个class方法一样可以使用async,只须要将async放在它以前就能够 就像这样:
async wait () {
       return await Promise.resolve(1)
   }
}
new Waiter().wait().then(alert) // 1
这里的意思是同样的:它确保了返回值是一个promise,支持await

复制代码

错误处理

若是一个promise正常resolve,那么await返回这个结果,可是在reject的状况下会抛出一个错误,就好像在那一行有一个throw语句同样。promise

async function f() {
    await Promise.reject(new Error('whoops!'))
}
复制代码

和下面同样

async function f() {
    throw new Error('Whoops!')
}   
复制代码

在真实的使用场景中,promise在reject抛出错误以前可能须要一段时间,因此await将会等待,而后才抛出一个错误。 咱们能够使用try-catch语句捕获错误,就像在正常抛出中处理异常同样:

async function f() {
    try {
        let response = await fetch('http://no-such-url')
    } catch (err) {
        alet(err) // TypeError: failed to fetch
    }
}
f()
复制代码

若是咱们不使用try-catch,而后async函数f()的调用产生的promise变成reject状态的话,咱们能够添加.catch去处理它:

async function f() {
    let response = await fetch('http://no-such-url')
}
// f()变成了一个rejected的promise
f().catch(alert) // TypeError: failed to fetch
复制代码
async/await可以与Promise.all友好的协做
当咱们须要等待多个promise时,咱们能够将他们包装在Promise.all中而后使用await:

// 直到数组所有返回结果
let results = await Promise.all([
   fetch(url1),
   fetch(url2),
   ...
])
若是发生了一个错误,它就像普通状况同样:从一个失败状态的promise到Promise.all,而后变成了一个咱们可以使用try-cathc去捕获的异常。
复制代码

参考文章async/await

4、将js中的异步回调例子修改

var mysql = require('mysql');
const mysql = function() {
    console.log('链接的database是', database)
    const url = {
        host     : 'localhost',
        user     : 'root',
        password : '123456',
        database : 'test'
    }
    var connection = mysql.createConnection(url);
       
    connection.connect();
    var mysqlQuery = new Promise((resolve, reject) => {
        var  sql = 'SELECT * FROM test1'
        connection.query(sql,function(err,result){
            if(err){console.log(err)}
            resolve(result)
        })
    }) 
    const result = await mysqlQuery(function(data) {
        return data
    })
    console.log(result)
    console.log(2)
}
mysql()
// 数据库查询结果
//2
复制代码

相关文章
相关标签/搜索