js中,如何将异步操作变为同步?

经常看到的一个题目,特此求解
gpt的写法是:

  1. async/await
  2. callback function
阅读 5.9k
3 个回答

严格来说异步没有办法变为同步。更多时候提问者应该是想说让代码写起来像同步。那么这样其实就只有一种那就是async/await;因为其他的方式都不太像同步。宽泛点问应该是怎么设计一个异步逻辑。那就有很多种了。
1、回调函数
2、promise
3、队列。其实promise也是队列
4、promise+generator => async/await

如果题主意思是让异步代码有类似同步的样子

一般也就是那两三种

  • async

    function asyncFunction() {
      return new Promise((resolve, reject) => {
        // 模拟异步操作
        setTimeout(() => {
          const result = 'Hello, world!';
          resolve(result);
        }, 1000);
      });
    }
    
    // 调用测试
    (async function() {
      console.log('Start');
    
      const result = await asyncFunction();
    
      console.log('End');
    })();
  • 回调函数

    function asyncFunction(callback) {
      // 模拟异步操作
      setTimeout(() => {
      const result = 'Hello, world!';
      callback(result);
      }, 1000);
    }
    
    // 调用测试
    (function syncFunction() {
      console.log('Start');
    
      asyncFunction(function(result) {
      console.log(result);
    
      console.log('End');
      });
    })();
  • Generator生成器

    function asyncFunction() {
      return new Promise((resolve, reject) => {
        // 异步操作
        setTimeout(() => {
          const result = 'Hello, world!';
          resolve(result);
        }, 1000);
      });
    }
    
    // 将异步操作封装在生成器中(不大推荐,不如上面两种简洁明了)
    function* syncFunction() {
      console.log('Start');
    
      const result = yield asyncFunction();
    
      console.log(result);
    
      console.log('End');
    }
    
    // 执行生成器函数(手动迭代)
    const generator = syncFunction();
    
    function handleAsync(iterator) {
      const { value, done } = iterator.next();
    
      if (done) return;
    
      if (value instanceof Promise) {
        value.then((result) => {
          handleAsync(iterator);
        }).catch((error) => {
          console.error(error);
        });
      }
    }
    
    handleAsync(generator);
  • 借助第三方框架,例如:

    • synchronize.js
    • fibers.js
    • (不推荐)可能导致性能下降和代码可读性降低

如果题主的意思是把异步代码改造为同步

那就要把所有会触发异步的代码移除或修改(正常不会有这样丧心病狂的需求吧)

例如:

  • 定时器函数
  • 监听事件处理
  • async 函数和 Promise 对象
  • ...
第三方框架链接
synchronize
fibers

一般来说将异步代码改为同步写法比较常见的就是封装后的各种回调函数以及借助Promise来实现,包括async/await在内实际上只是改变了代码的写法使其看起来更加同步,但底层运行逻辑仍是异步的,这里提一个以前开发项目用过的node扩展deasync.js,核心功能是用c++写的,在node环境下需要经过node-gyp编译后才能使用,底层逻辑是通过强制刷新一遍事件循环来达到真正意义上的异步代码同步化执行,使用方法也十分简单粗暴:

var deasync = require('deasync');
// 经过deasync包装后的exec方法已变成同步函数
var cp = require('child_process');
var exec = deasync(cp.exec);
try {
    console.log(exec('ls -la'));
} catch (error) {
    console.log(error);
}
// done会如预期那样在最后打印出来
console.log('done');
var data, done = false;
// asyncFunction是一个请求数据的接口
asyncFunction(p1, function cb(res) {
    data = res;
    done = true;
});
require('deasync').loopWhile(function() { return !done; });
// 调用loopWhile等待后此时已经能获取到赋值后的data
function SyncFunction() {
    var ret;
    setTimeout(function() {
        ret = "hello";
    }, 3000);
    // 调用sleep方法睡眠一段时间直到ret被赋值
    while (ret === undefined) {
        require('deasync').sleep(100);
    }
    // 该函数将会返回hello
    return ret;
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题