异步

  • 函数对象:将函数作为对象使用
  • 实例对象:new 函数产生的对象,简称对象obj
function Fn(){}
const fn = new Fn()//Fn是构造函数,fn是实例对象
console.log(Fn.prototype) //Fn是函数对象(将函数作为对象使用 Fn.了)

同步异步

  • 同步:代码从上往下执行,遇见同步,就一直等,等到同步完成,才会继续执行(一次只能处理一件事情,当前这件事情处理完,才能继续处理下一件事情)
  • 异步:代码从上往下执行,遇见异步,就先走了,异步的代码后面执行(比如定时器,ajax,事件处理,nodejs读取文件也有异步)同时可以进行好几件事情(一般是基于多线程并发完成的)

JS 中的异步编程,有自己一些特殊的处理方式:队列 Queue,事件循环 EventLoop

//同步函数:接收a,b两个参数,返回a+b
function sum(a, b){
	return a+b;
}
var m = sum(1, 2)

setTimeout(js 函数, 等待的毫秒数)
设定一个指定等候时间, 时间到了, 浏览器就会执行一个指定的代码

//接收a,b两个参数,2000毫秒后返回a+b
function sumAfer2000ms(a, b, callback){
	setTimeout(function(){ //第一个参数是回调函数
		callback(a+b); //不能直接return a+b,这个return只是setTimeout回调函数的返回,sumAfer2000ms并没有return
	}, 2000);
}
sumAfer2000ms(1, 2, function(m){
	console.log(m);
})
console.log('ok');

先输出ok ,2000ms后输出3

回调黑洞 callback hell

sumAfer2000ms(1, 2, function(m){
	console.log(m);//2s之后
	sumAfer2000ms(1, 2, function(m){//上一个的2s之后
		console.log(m);
		....
})

回调函数

回调函数 1.自己定义的 2.没有亲自调用 3.但最终执行了(在一定条件下或某个时刻)
常用的回调函数
dom事件回调函数,定时器回调函数,ajax请求回调函数,生命周期回调函数

回调函数的两种类型

  • 同步回调:立即执行,执行完了才结束,不会放入回调队列中。(数组遍历相关的回调函数/Promise的excutor函数)
  • 异步回调:不会立即执行,会放入回调队列中将来执行(定时器回调/ajax回调/Promise的成功|失败回调)
    在发起一个异步任务的同时指定一个函数,在异步任务完成时会自动的调用这个函数
//同步回调函数
const arr = [1,3,5]
arr.forEach(item => { //遍历回调
    console.log(item);
})
console.log('foreach()之后');
// 异步回调函数
setTimeout(()=>{
    console.log('timeout callback()');
},0)
console.log('setTimeout()之前');

Promise

Promise颠覆了“同步函数可以用变量接收,异步函数必须写回调”
Promise就是一个语法糖,改写的东西还是写了,比如形参callback,只不过就是叫做resolve了;以前传入回调函数的参数m,现在在then()里面传
好处:可以连续then(),不会回调黑洞了

then()是Promise对象实例的方法

function sumAfter2000ms(a, b){ //返回一个Promise实例
	return new Promise((resolve, reject) =>{
		setTimeout(function(){
			resolve(a+b);
		}, 2000);
	});
}
sumAfter2000ms(1, 2)
.then(m => {
	console.log(m);
})

写法一,异步调用:将回调函数作为函数的参数

$.get('/',function(data){console.log(data.length)}) 

写法二,将回调函数写在.then()

fetch('/').then(
	(res)=>res.text()).then(data=>console.log(data.length)
) 

new Promise的时候,里面的内容会立即执行(同步) 因而为了能实现调用时执行,Promise一般都是作为函数的返回值

resolve接收正确结果,导入then中(resolve(XX) 接的是.then(xx))
reject接收错误,导入catch中

setTimeout(function(){console.log(123)},2000)

//2s之后,调用resolve(123)
new Promise((resolve,reject)=>{
    setTimeout(function(){resolve(123)},2000);//标记一,此处是传给then的
}).then(res=>{console.log(res)})

promise.then()说明此时promise由之前的pending状态(见下面代码),转为resolve状态,开始执行标记一的地方
then()执行就是标记一的地方执行,现在在then()里面传入的res 对应 传入回调函数的参数123


分解开

var p1 = ()=> new Promise((resolve,reject)=>setTimeout(()=>resolve(12345),2000))
p1()//调用p1,返回pending状态的promise对象
Promise {<pending>}([[PromiseStatus]]: "pending")

async / await

async/await 允许我们使用同步的写法来写异步,使用变量接收异步的结果

//命令台运行的
async function func(){
    var res = await p1();//这里会等待成功,才执行下面
    console.log(res)
}
func()//过了2s
Promise {<pending>}:[[PromiseStatus]]: "resolved"
12345

也可以用then实现

function q2(){
    p1().then(res=>console.log(res))
}
q2()
12345

调用resolve()能够将Promise对象变为resolved状态
调用reject()能够将Promise对象变为rejected状态

当且仅当async修饰函数后,函数内可以使用await
await的后面必须跟着一个返回promise对象的函数

await p1() 返回promise运行完之后的结果(resolve中的结果),即2s后输出的12345

  • await会拿到resolve的数据或者是传给then的数据(await代表resolve了),是then函数的语法糖
  • 而reject是通过try…catch…拿到的

async/await原理:async,await 是Generator+ yield的语法糖
Generator函数,里面的代码分段执行,看到yield就给你分一段

function* helloworldGenerator(){
	yield 'hello'; //yield类似暂停标记, 指向hello
	yield 'world';
	return 'ending';
}
var hw = helloworldGenerator(); //hw迭代器
console.log(hw.next());//next表示 拿出这个暂停的值,
console.log(hw.next());
console.log(hw.next());

then调用链的秘密

1 then的传递性:promise().then(x=>y).then(z=>z) 这里第二个then的输入参数z就是上一个then返回值传递过来的y。
2 then传递时的变化: 如果上面y是个promise,则z是promise执行完之后的结果(resolve中的结果)!!!!

上面解释了fetch().then(res=>res.text()).then(data=>console.log(data))。这里面res.text()得到的是个promise,所以传到下一个then中的data会被’偷偷’解析成运行完的结果。

而axios可以直接console.log(res.data)是因为axios和fetch是不同的函数封装,axios直接把内容封到data属性中了,而非再运行个函数


例子

封装一个promise


读取文件时的异步操作

redux-saga 有异步的

        $.ajax({
            url: '',
            success: function (res) {
                console.log(res);
            }
        })
        //Promise(回调函数)
        let promise = new Promise(function (resolve, reject) {
            //  成功的函数resolve,失败的函数reject
            resolve(1);//此时会调用then里第一个参数所代表的函数
        })

        //promise是new的Promise实例,有固定写法
        // promise.then(成功的函数resolve,失败的函数reject) 与上面对应,是实参,上面是代号是定义
        promise.then(function (data) {//resolve(1);
            console.log('成功', data);
        }, function () { })

        //ajax放在promise里面,只有promise.then时才会拿到结果
        let promise1 = new Promise(function (resolve, reject) {
            $.ajax({
                url: '',
                success: function (res) {
                    resolve(res);//成功时,调用resolve函数
                }
            })
        })
        //没有那么多嵌套关系,是一个链式调用
        promise1
        .then(function (res) {
            console.log('ajax成功', res);
            let p2 = new Promise(function (resolve, reject) { })
            return p2
        })
        .then(function (res) { })

        //axios就是用promise把发送ajax封装一遍
        function axios() {
            let p1 = new Promise(function (resolve, reject) {
                $.ajax({
                    url: '',
                    success: function (res) {
                        resolve(res);//成功时,调用resolve函数
                    }
                })
            })
            return p1//axios返回一个promise
        }//axios()调用
        axios().then(function (res) { })

        //点击按钮,发送ajax
        document.getElementById("btn").onclick = ()=>{
            axios().then(function(res){
                console.log('成功',res);
            })
        }
        //async await可以省掉then
        document.getElementById("btn").onclick = async ()=>{
            let res = await axios()//这里会等待成功,才执行下面
            //await类似同步,axios()返回后,才会执行后面的
            console.log('成功',res);   
        }

        // Promise.all(数组,第二个参数是函数)
        // 必须数组里面的所有promise执行完毕才算成功
        Promise.all([p1,p2,p3]),function);
        //只要数组里面的任何一个成功,promise执行完毕就算成功
        Promise.race([p1,p2,p3]),function)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值