如何确保不会将内容替换为旧的回复?

时间:2019-11-14 19:12:04

标签: javascript node.js reactjs promise

所有人的美好一天,

我正在做一个React课程,并且已经将代码提交给了审阅者。他给我发了几条评论,有一条我无法解决。

评论如下:

  

检查(query === this.state.query)以确保您不会将内容替换为旧的响应

部分代码如下:


updateQuery = (query) => {

        this.setState({

          query: query

        })

        this.updateWantedBooks(query);
      }

updateWantedBooks = (query) => {

        if (query) {

          BooksAPI.search(query).then((wantedBooks) => {

            if (wantedBooks.error) {

              this.setState({ wantedBooks: [] });

            } else {

this.setState({ wantedBooks: wantedBooks });

            }       

          })

        } else {

          this.setState({ wantedBooks: [] });

        }

      }

任何人都可以帮助我我该怎么办?

致谢。

4 个答案:

答案 0 :(得分:2)

代码审查者是正确的,如果用户输入了相同的查询,您真的不想替换响应。

您必须将用户最近搜索过的内容存储在某个地方:

this.setState({ wantedBooks: [], query });

如果成功响应:

this.setState({ wantedBooks, query });

然后在进行进一步搜索时进行检查:

if (query && query !== this.state.query) {
    // continue the search only if query is different that current

答案 1 :(得分:1)

您可以使用工厂函数来更安全地诱捕成员,而不是依赖于其他代码容易滥用的外部成员。

您已经发现,诱捕和测试query == this.state.query可以正常工作,但可以说不是最佳的解决方案。

稍加思考,您就可以自动强制updateWantedBooks()的每次调用拒绝同一功能(如果尚未解决)返回的上一个承诺,从而使任何成功链接到上一个承诺的回调不会触发其错误路径。

这可以通过可重复使用的canceller实用程序来实现,该实用程序接受两个回调并利用Promise.race(),如下所示:

// reusable cancellation factory utility
function canceller(work, successCallback) {
    var cancel;
    return async function(...args) {
        if (cancel) {
            cancel(new Error('cancelled')); // cancel previous
        }
        return Promise.race([
            work(...args),
            new Promise((_, reject) => { cancel = reject }) // rejectable promise
        ]).then(successCallback);
    };
};

这是一个演示...

// reusable cancellation factory utility
function canceller(work, successCallback) {
	var cancel;
	return async function(...args) {
		if (cancel) {
			cancel(new Error('cancelled')); // cancel previous
		}
		return Promise.race([
			work(...args),
			new Promise((_, reject) => { cancel = reject })
		]).then(successCallback);
	};
};

// delay utility representing an asynchronous process
function delay(ms, val) {
	return new Promise(resolve => {
		setTimeout(resolve, ms, val);
	});
};

function MySpace() {
	// establish a canceller method with two callbacks
	this.updateWantedBooks = canceller(
		// work callback
		async (query) => delay(500, query || { 'error': true }), // a contrived piece of work standing in for BooksAPI.search()
		// success callback
		(wantedBooks => this.setState(wantedBooks)) // this will execute only if work() wins the race against cancellation
	);
	this.setState = function(val) {
		console.log('setState', val);
		return val;
	};
};

var mySpace = new MySpace();
mySpace.updateWantedBooks({'value':'XXX'}).then(result1 => { console.log('result', result1) }).catch(error => { console.log(error.message) }); // 'cancelled'

mySpace.updateWantedBooks(null).then(result2 => { console.log('result', result2) }).catch(error => { console.log(error.message) }); // 'cancelled'

mySpace.updateWantedBooks({'value':'ZZZ'}).then(result3 => { console.log('result', result3) }).catch(error => { console.log(error.message) }); // {'value':'ZZZ'} (unless something unexpected happened)

请注意,canceller()不会尝试中止它启动的异步过程,而是会阻碍返回的Promise的成功路径,而倾向于错误路径。

答案 2 :(得分:0)

我认为审阅者的观点是Search API的响应是异步的,并且在用户改变主意并已请求搜索“ query 2”之后,“ query 1”的结果才能到达。因此,当响应到达时-我们需要检查我们是否真的对此感兴趣:

 updateQuery = query => {
    this.setState({
      query: query
      wantedBooks: []
    })
    this.updateWantedBooks(query);
  }

updateWantedBooks = query => {
    if (query) {
      BooksAPI.search(query).then((wantedBooks) => {
        // if updateQuery("query1) and updateQuery("query2") called in a row
        // then response for query1 can arrive after we requested query2
        // => for some period of time we'll show incorrect search results
        // so adding check if query still the same can help
        if (query !== this.state.query) {
          // outdated response
          return;
        } else if (wantedBooks.error) {
           // query is okay, but server error in response
           this.setState({
              wantedBooks: []
           })
        } else {
           // success response to requested query
           this.setState({ wantedBooks });
        }
     })
  }
}

答案 3 :(得分:0)

伙计们,我用您的答案做了一些测试,但是我意识到代码在某种程度上表现得很奇怪。

因此,我在审阅者评论的其他部分中看到了我以前没有看过的部分,在这里做我的回答,即以下评论:

  

在promise的'then'部分中检查if(query === this.state.query),以确保您不会将内容替换为旧的响应。

这个“内在”然后在我的大脑中跳动。

所以,我想我已经达到了令人满意的代码;当然,也许这不是确定的解决方案,这就是为什么我要在这里展示给您,并在需要改进的地方随时发表评论。我在下面放了代码:


updateQuery = (query) => {

        this.setState({

          query: query

        })

        this.updateWantedBooks(query);

      }


      updateWantedBooks = (query) => {

        if (query) {

          BooksAPI.search(query).then((wantedBooks) => {

            if (wantedBooks.error) {

              this.setState({ wantedBooks: [] });

            } else if (query !== this.state.query) {

              this.setState( { wantedBooks: [] });

            } else {

              this.setState({ wantedBooks: wantedBooks });

            } 

          })

        } else {

          this.setState({ wantedBooks: [] });

        }    

      }

致谢