JS:使用异步函数来暂停操作

时间:2018-10-21 05:24:44

标签: javascript es6-promise

我正在为Google搜索结果创建网络扫描仪。我希望用户能够在搜索结果时暂停程序。最初,我尝试使用while循环暂停它,但是由于JS是单线程的,因此会冻结程序。有人告诉我可以使用Promises修复此问题,但是暂停时代码仍然冻结,并且我无法恢复程序。

我如何正确地使其异步工作?

var pause = false;
var q = 'query';
fetchUrls(q);

function fetchUrls(q, page = 0) {
    PAUSE().then(function () {
        request(`https://www.google.com/search?q=${q}&start=${page}`, (error, response, htmlString) => {
            if (!error && response.statusCode == 200) {
                // Do whatever I want with the page data
                page += 10;
                fetchUrls(q, page);
            }
        });
    });
}

function PAUSE() {
    return new Promise(resolve => {
        if (pause) {
            $('.pause-button').addClass('hidden');
            $('.resume-button').removeClass('hidden');
        }
        // Pause the program
        while (pause) {
        }
        $('.pause-button').removeClass('hidden');
        $('.resume-button').addClass('hidden');
        resolve(true);
    });
}

$(document).on('click', '.pause-button', function() {
    pause = true;
});

$(document).on('click', '.resume-button', function() {
    pause = false;
});

1 个答案:

答案 0 :(得分:0)

处理状态非常困难,因此,我建议您使用像 react 这样的现代框架。这也将帮助您构建代码。

了解诺言,我认为您已经改变了那时的角色以及诺言任务。

// this should be maybe on the promise creator
 request(`https://www.google.com/search?q=${q}&start=${page}`, (error, response, htmlString) => {
    if (!error && response.statusCode == 200) {
        // Do whatever I want with the page data
        page += 10;
        // fake the request to test it in isolation
        fetchUrls(q, page);
    }
    });


// this should be when resolving, on the method .then
return new Promise(resolve => {
    if (pause) {
        $('.pause-button').addClass('hidden');
        $('.resume-button').removeClass('hidden');
    }
    // Pause the program
    while (pause) {
    }
    $('.pause-button').removeClass('hidden');
    $('.resume-button').addClass('hidden');
    resolve(true);
});

本主题:承诺,回调,状态更改都不容易...

我已经为您的代码创建了工作版本,并带有模拟请求的功能,这意味着您可以进行伪造的请求。正如我所说,我希望这将有助于您阐明一些概念。即使您想将此代码转换回原始javascript。

const fakeRequest = (url,callback) => {
  const time = 300 + Math.random()*1800;
  console.log("Fetching "+url+" ...");
  setTimeout(() => {
    console.log("Elapsed "+Math.round(time)+"ms");
    let error,response = {};
    if (Math.random() > 0.1){
      error = false;
      response.statusCode = 200;
    }else{
      error = true;
    }
    callback(error,response,'<HTML/>');
  },time);
};



class UrlFetcher extends React.Component {
  constructor() {
    super();
    this.state = {paused:true, page:0};
    //this.handleOnChange = this.handleOnChange.bind(this);
  }

  
  onClick()  {
    return () => {
      if (this.state.paused) 
        this.fetchUrls('query');
      this.setState((state, props) => {
        state.paused = !state.paused; 
        return state;
      });
      
    }
  }
  
  fetchUrls(q) {
    console.log('Promising');
    return new Promise((resolve,reject) => {
       fakeRequest(`https://www.google.com/search?q=${q}&start=${this.state.page}`, (error, response, htmlString) => {
            if (!error && response.statusCode == 200) {
                // Do whatever I want with the page data
                console.log("Request HIT");
                resolve(true);
            }else{
                console.log("Request FAILED");
                resolve(false);
            }
        });
        
    }).then(()=>{
        if (!this.state.paused){
          this.setState((state, props) => {
            state.page += 10
            return state;
          });
          
          this.fetchUrls(q);
        }
    });
}

  render() {
    
    const btnStates = {
      true : {text: 'Launch', class: 'launch-button'},
      false  : {text: 'Pause', class: 'pause-button'}
    };
    const btn = btnStates[this.state.paused];
    
    return (
      <button class={btn.class} onClick={this.onClick()}>
      {btn.text}
      </button>
    
    )
  }
}

ReactDOM.render(<UrlFetcher />, document.getElementById('urlfetcher'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="urlfetcher"></div>