跳至主要內容

JavaScript 异步编程

LincZero大约 3 分钟

JavaScript 异步编程

callback函数

promise

ES10 - asyn - await

踩坑

callback回调函数

调用函数
function functionA(callbake){}
functionA(()=>{})
会识别为传入的是一个对象

改法:
function functionA(null, callbake){}
functionA(null,()=>{})

原因好像是因为第一个必须是Error,就算没有也要返回null
便于错误后不调用callback

promise执行顺序

then里嵌套的then优先级少于该then同级往下!即:

.then(()=>{
    // 执行1
    .then(()=>{
        // 执行3
    })
    .then(()=>{
        // 执行4
    })
})
.then(()=>{
    // 执行2
})

【总结、比较、原理、写法互转】

比较then和aysnc-await

(以下函数,都优化成能直接在控制台运行,可以方便调试)

// 异步函数A
// 输出顺序:
//   a0.start -> a0.returnFake -> a0.2s
let getPromise = ()=>{
    return new Promise((resolve, reject) => {
        console.log("a0. start")
        setTimeout(() => {
            console.log("a0. 2s")
            resolve("a0. returnTrue")
        }, 2000);
        console.log("a0. returnFake")
    });
}
getPromise()

// 函数B调用异步函数A - then方案
// 输出顺序:
//   b1.start -> a0.start -> a0.returnFake -> b1.return -> a0.2s -> b1.getReturn: a0.returnTrue
let b1 = ()=>{
    console.log("b1. start")					// 1
    getPromise().then((item)=>{                 // 外2, 内4
        console.log("b1. getReturn: ", item)    // 5
    })
    console.log("b1. return")                   // 3
}
b1()

// 函数B调用异步函数A - await方案
// 输出顺序:
//   b2.start -> a0.start -> a0.returnFake -> a0.2s -> b2.getReturn: a0.returnTrue -> b2.return
let b2 = async ()=>{
    console.log("b2. start")					// 1
    let item = await getPromise()               // 外2, 内3
	console.log("b2. getReturn: ", item)        // 4
    console.log("b2. return")                   // 5
}
{
    console.log("b3. start")					// 0.5
	b2()										// 见上
    console.log("b3. over")						// 2.5
}

本质是一样的

同步函数调用Promise函数的场景中,比较区别:

  1. setTimeout相当于多了一条线程在工作,与主线程无关,主线程没有方法获取子线程的返回值
  2. Promise-Then方案,相当于往子线程传递一个回调函数,回调函数对应的是 then(...) 里面的内容!
  3. Async-Await方案,相当于往子线程传递一个回调函数,回调函数对应的是 await ... 该行代码的往下的所有内容!

(当然,在js中,其实这是伪的多线程,只是类比好说明)

主线程如何获取子线程的返回值?

promise和await方案,都没有真正做到这一点。

……如果按其他语言的思路,那么就是利用线程之间的共享变量来做到

当我发现,做不到

// 异步函数A
// 输出顺序:
//   尝试:待变动 -> 尝试:变动了
let promiseChange = (global)=>{
    return new Promise((resolve, reject) => {
        console.log("尝试:待变动", global)
        setTimeout(() => {
            global.flag = 1;
            console.log("尝试:变动了", global)
        }, 2000);
    });
}
promiseChange(global)

// 函数B调用异步函数A - then方案
// 输出顺序:
//   预期:尝试:待变动 -> 检测:未变动 -> 检测:未变动 -> 尝试:变动了 -> 检测:变动了
//   实际:尝试:待变动 -> 检测:未变动 -> 检测:未变动 -> ... -> 尝试:变动了
// 失败分析:
//   看起来js的 `delay` 把setTimeout线程也给一起延时了,可能是因为js的setTimeout不是真正的多线程?
let global = {
	flag: 0
};
let c = ()=>{
    promiseChange(global)
	for (let i = 0; i<10; i++) { // 10s超时
        if (global.flag == 0) {console.log("检测:未变动", global); }
		else {console.log("检测:变动了", global); break; }
        delay(1000)
    }
}
c()

不要擅自帮我修改成then和await方法,假设函数c是一个接受number变量的回调函数,在无法修改函数c参数类型的前提下,我在尝试是否有可能能让c返回一个number变量

……感觉没什么方法,同步调用异步 这一行为,在其他语言中可能我能想一些骚操作能做到。反正js中可能只能老老实实用promise和await了